diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..71da63f2
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,38 @@
+# THIS FILE WAS AUTOGENERATED; DO NOT EDIT.
+# Source: config/toolconfigsrc/editorconfig.
+
+# Common config file for supported editors; see editorconfig.org.
+# If you are using an editor that doesn't support editorconfig, try to
+# conform to these settings manually.
+
+# Note: while we autogenerate this file, we also check it into git
+# because it affects how source is displayed on github.
+
+# This is the top-most EditorConfig file.
+root = true
+
+# Defaults for all files.
+[*]
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# Python overrides.
+[*.py]
+indent_style = space
+indent_size = 4
+max_line_length = 79
+charset = utf-8
+
+# Makefile overrides.
+[Makefile]
+indent_style = tab
+indent_size = 2
+max_line_length = 80
+
+# C/C++ overrides.
+[*.{c,cc,h,cpp,hpp}]
+indent_style = space
+indent_size = 2
+max_line_length = 80
+
diff --git a/.efrocachemap b/.efrocachemap
index 0ef6ded0..eeb8e3b8 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -1,457 +1,458 @@
{
- "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/data/langdata.json": "https://files.ballistica.net/cache/ba1/1d/dc/d529c3d37b5765384fab6d17275b",
- "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/1e/40/fe46af4877b3de1fbc89db3bedb1",
- "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/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/audio/achievement.ogg": "https://files.ballistica.net/cache/ba1/48/7a/450eebf6b07284ca08a932894e3a",
+ "assets/build/ba_data/audio/actionHero1.ogg": "https://files.ballistica.net/cache/ba1/c0/37/37f7f7a2dee78aba74a5e790a1b8",
+ "assets/build/ba_data/audio/actionHero2.ogg": "https://files.ballistica.net/cache/ba1/33/ae/6bb0fbd767162effa1be818da77f",
+ "assets/build/ba_data/audio/actionHero3.ogg": "https://files.ballistica.net/cache/ba1/d3/6b/90193dca492df0d11b42960f8b40",
+ "assets/build/ba_data/audio/actionHero4.ogg": "https://files.ballistica.net/cache/ba1/f1/96/09af46e756b49dc92f9f4e46b5b3",
+ "assets/build/ba_data/audio/actionHeroDeath.ogg": "https://files.ballistica.net/cache/ba1/3f/09/feffcda3fb6ca9ab013781693b65",
+ "assets/build/ba_data/audio/actionHeroFall.ogg": "https://files.ballistica.net/cache/ba1/66/87/10ce556e96ee0271e2d40b33d92b",
+ "assets/build/ba_data/audio/actionHeroHit1.ogg": "https://files.ballistica.net/cache/ba1/a7/1a/43c67d75c559388d05579f7887cd",
+ "assets/build/ba_data/audio/actionHeroHit2.ogg": "https://files.ballistica.net/cache/ba1/eb/a9/71e16a5e2aa6603f63d8aedfc1b5",
+ "assets/build/ba_data/audio/activateBeep.ogg": "https://files.ballistica.net/cache/ba1/2e/a4/a8569c885ff56de579c1c2aec17b",
+ "assets/build/ba_data/audio/agent1.ogg": "https://files.ballistica.net/cache/ba1/29/6c/136590efd49011f7b79dabb1e66c",
+ "assets/build/ba_data/audio/agent2.ogg": "https://files.ballistica.net/cache/ba1/e1/b3/cd90ec94923ca9f66018dd536c7c",
+ "assets/build/ba_data/audio/agent3.ogg": "https://files.ballistica.net/cache/ba1/8b/a0/bd3473f2a2cc2ddcda4368e80a9a",
+ "assets/build/ba_data/audio/agent4.ogg": "https://files.ballistica.net/cache/ba1/44/c7/3d9149f01b3c92af49879095e37c",
+ "assets/build/ba_data/audio/agentDeath.ogg": "https://files.ballistica.net/cache/ba1/9b/44/709daabf7bb993ab1251a0ef19fa",
+ "assets/build/ba_data/audio/agentFall.ogg": "https://files.ballistica.net/cache/ba1/20/4b/44bafb0842adb2446aa1cbd0daa8",
+ "assets/build/ba_data/audio/agentHit1.ogg": "https://files.ballistica.net/cache/ba1/1c/eb/b616cef8de9ca2e3477baf536c43",
+ "assets/build/ba_data/audio/agentHit2.ogg": "https://files.ballistica.net/cache/ba1/2c/34/2a04b86a486051ab2e580b35948d",
+ "assets/build/ba_data/audio/alarm.ogg": "https://files.ballistica.net/cache/ba1/d0/64/883b4a29d774d8c3e6b0c534627b",
+ "assets/build/ba_data/audio/ali1.ogg": "https://files.ballistica.net/cache/ba1/e9/9f/2176f47bf0e9e6203ba641f82c77",
+ "assets/build/ba_data/audio/ali2.ogg": "https://files.ballistica.net/cache/ba1/cf/62/57e9a4783913c1f7f43fae8778c4",
+ "assets/build/ba_data/audio/ali3.ogg": "https://files.ballistica.net/cache/ba1/27/75/c2ef59ef68e9f5afba10884a0864",
+ "assets/build/ba_data/audio/ali4.ogg": "https://files.ballistica.net/cache/ba1/ab/69/47eeeaef5e51d6ca75211ff48665",
+ "assets/build/ba_data/audio/aliDeath.ogg": "https://files.ballistica.net/cache/ba1/d0/6c/416576164fe81ddec15ca134d7e5",
+ "assets/build/ba_data/audio/aliFall.ogg": "https://files.ballistica.net/cache/ba1/e3/5b/ff8b8fbd7ad75fac2bb4cd111e35",
+ "assets/build/ba_data/audio/aliHit1.ogg": "https://files.ballistica.net/cache/ba1/50/ce/b369876a110b91239837c927f4b9",
+ "assets/build/ba_data/audio/aliHit2.ogg": "https://files.ballistica.net/cache/ba1/28/b6/3c41e3d3b77c2e283cbd6fecfdda",
+ "assets/build/ba_data/audio/alien1.ogg": "https://files.ballistica.net/cache/ba1/0c/8d/c0452affd3f3bc7c70b66c675a26",
+ "assets/build/ba_data/audio/alien2.ogg": "https://files.ballistica.net/cache/ba1/53/e2/b58aaea530ac9c27bdde44b9c22e",
+ "assets/build/ba_data/audio/alien3.ogg": "https://files.ballistica.net/cache/ba1/db/86/08bc6014a162436c6ad1ee31786f",
+ "assets/build/ba_data/audio/alien4.ogg": "https://files.ballistica.net/cache/ba1/48/56/5a9afa4b2e2829e2d8bda9252ddf",
+ "assets/build/ba_data/audio/alienDeath.ogg": "https://files.ballistica.net/cache/ba1/bd/18/e079531ac28454d8fd7e38b0b7e9",
+ "assets/build/ba_data/audio/alienFall.ogg": "https://files.ballistica.net/cache/ba1/19/ea/3bd275cd2269102caf6ea328f2e5",
+ "assets/build/ba_data/audio/alienHit1.ogg": "https://files.ballistica.net/cache/ba1/d4/c0/d7fc223e2defa08f9cea1c96e5f8",
+ "assets/build/ba_data/audio/alienHit2.ogg": "https://files.ballistica.net/cache/ba1/72/2a/61ccb4cea94e26245b8542ab3764",
+ "assets/build/ba_data/audio/announceEight.ogg": "https://files.ballistica.net/cache/ba1/80/7a/933870b2eec3d836c36c192c9215",
+ "assets/build/ba_data/audio/announceFive.ogg": "https://files.ballistica.net/cache/ba1/eb/fc/a16fc7cb51edd9e7da768a80fe59",
+ "assets/build/ba_data/audio/announceFour.ogg": "https://files.ballistica.net/cache/ba1/4d/e8/edaa8df382c309864ddd8e767bdb",
+ "assets/build/ba_data/audio/announceNine.ogg": "https://files.ballistica.net/cache/ba1/03/c0/2125a9d5b458f610c40d5e2821d0",
+ "assets/build/ba_data/audio/announceOne.ogg": "https://files.ballistica.net/cache/ba1/05/ba/f94690d2b833083b062f8a3aa5b2",
+ "assets/build/ba_data/audio/announceSeven.ogg": "https://files.ballistica.net/cache/ba1/af/5d/25803762adf4fc7cb32ce1d9ea78",
+ "assets/build/ba_data/audio/announceSix.ogg": "https://files.ballistica.net/cache/ba1/b5/25/08b9f4890f2211c6e37ef378e0e7",
+ "assets/build/ba_data/audio/announceTen.ogg": "https://files.ballistica.net/cache/ba1/6c/f0/8924407cbf270bb8136e9920a222",
+ "assets/build/ba_data/audio/announceThree.ogg": "https://files.ballistica.net/cache/ba1/6a/51/0fdba9085200e83c5e5d80a325dc",
+ "assets/build/ba_data/audio/announceTwo.ogg": "https://files.ballistica.net/cache/ba1/1b/5d/119c564ed55ffc97e833cb130b78",
+ "assets/build/ba_data/audio/assassin1.ogg": "https://files.ballistica.net/cache/ba1/d7/c3/07a7527aa41337f143b3b0f15d15",
+ "assets/build/ba_data/audio/assassin2.ogg": "https://files.ballistica.net/cache/ba1/67/47/e3154460065f5baef57f4fcc24e9",
+ "assets/build/ba_data/audio/assassin3.ogg": "https://files.ballistica.net/cache/ba1/4d/16/3424f9cf3e03c97c596082282b1c",
+ "assets/build/ba_data/audio/assassin4.ogg": "https://files.ballistica.net/cache/ba1/5d/ab/5a3a4790507dfbce9a0d9bb21319",
+ "assets/build/ba_data/audio/assassinDeath.ogg": "https://files.ballistica.net/cache/ba1/c6/c9/4d1b4c7314d860194d20716348b1",
+ "assets/build/ba_data/audio/assassinFall.ogg": "https://files.ballistica.net/cache/ba1/30/10/2958aa576fa9f11235a749946701",
+ "assets/build/ba_data/audio/assassinHit1.ogg": "https://files.ballistica.net/cache/ba1/19/d0/c3fdf5678f659a1ee7964768a600",
+ "assets/build/ba_data/audio/assassinHit2.ogg": "https://files.ballistica.net/cache/ba1/f7/11/b255b849a67d68c5035cc68ada44",
+ "assets/build/ba_data/audio/bear1.ogg": "https://files.ballistica.net/cache/ba1/fd/b9/c78daf935f6570a4237b92da34d1",
+ "assets/build/ba_data/audio/bear2.ogg": "https://files.ballistica.net/cache/ba1/9e/fe/0c4936a1bb9a415264efbc71f1cb",
+ "assets/build/ba_data/audio/bear3.ogg": "https://files.ballistica.net/cache/ba1/56/c5/4372226dac57360c0be86f0fa0ad",
+ "assets/build/ba_data/audio/bear4.ogg": "https://files.ballistica.net/cache/ba1/2e/84/29707497e7397e29273f26c03eec",
+ "assets/build/ba_data/audio/bearDeath.ogg": "https://files.ballistica.net/cache/ba1/65/2c/0216a11fe57933064ee4788ed0b4",
+ "assets/build/ba_data/audio/bearFall.ogg": "https://files.ballistica.net/cache/ba1/37/6b/ce0e867d2b8ce33b79d938831b7b",
+ "assets/build/ba_data/audio/bearHit1.ogg": "https://files.ballistica.net/cache/ba1/5e/9d/cfb3f41abed5bba09be639697090",
+ "assets/build/ba_data/audio/bearHit2.ogg": "https://files.ballistica.net/cache/ba1/25/d4/6344ddd1699d6b2381c693d6db7f",
+ "assets/build/ba_data/audio/bellHigh.ogg": "https://files.ballistica.net/cache/ba1/19/61/cb59e4a168d48e36c97d3c0308d9",
+ "assets/build/ba_data/audio/bellLow.ogg": "https://files.ballistica.net/cache/ba1/7a/df/9f97638d1e15fad0eb2f7def2481",
+ "assets/build/ba_data/audio/bellMed.ogg": "https://files.ballistica.net/cache/ba1/7f/e5/aa326810dbfa488b62a35919c6b4",
+ "assets/build/ba_data/audio/bigImpact.ogg": "https://files.ballistica.net/cache/ba1/07/1b/786764577df3bb6fc63d898eb980",
+ "assets/build/ba_data/audio/bigImpact2.ogg": "https://files.ballistica.net/cache/ba1/ce/95/9cd7b0ba758e197d4021179367c8",
+ "assets/build/ba_data/audio/blank.ogg": "https://files.ballistica.net/cache/ba1/bf/59/4a4a3fe3ba656507bb9a9e35c944",
+ "assets/build/ba_data/audio/blip.ogg": "https://files.ballistica.net/cache/ba1/6f/05/5053369ead852ff3c793f47d42ec",
+ "assets/build/ba_data/audio/block.ogg": "https://files.ballistica.net/cache/ba1/36/88/4a7250afc5ce047b378c728a60b4",
+ "assets/build/ba_data/audio/bombDrop01.ogg": "https://files.ballistica.net/cache/ba1/9f/08/0260d66fb5be4cacbb946e883f7d",
+ "assets/build/ba_data/audio/bombDrop02.ogg": "https://files.ballistica.net/cache/ba1/16/c6/48cecf1ec4cff2b9cf2ed0a819c9",
+ "assets/build/ba_data/audio/bombRoll01.ogg": "https://files.ballistica.net/cache/ba1/e6/c6/c0f7d8aa27ad014098983ac1ee8e",
+ "assets/build/ba_data/audio/bones1.ogg": "https://files.ballistica.net/cache/ba1/86/bf/d266bb6873b6536d27d80e4eafaa",
+ "assets/build/ba_data/audio/bones2.ogg": "https://files.ballistica.net/cache/ba1/7b/22/df9d63f8f9e6a39038624d1be4bb",
+ "assets/build/ba_data/audio/bones3.ogg": "https://files.ballistica.net/cache/ba1/4b/8f/170895d0ff38f1d66dec541a419a",
+ "assets/build/ba_data/audio/bonesDeath.ogg": "https://files.ballistica.net/cache/ba1/07/80/ff15a67d5e5c6f8ce5b73cf2960e",
+ "assets/build/ba_data/audio/bonesFall.ogg": "https://files.ballistica.net/cache/ba1/9c/2e/e5e6bc3017019204228c7c1e2445",
+ "assets/build/ba_data/audio/boo.ogg": "https://files.ballistica.net/cache/ba1/f9/50/03bb1fbe572ba4c05b55c9164f1d",
+ "assets/build/ba_data/audio/boxDrop.ogg": "https://files.ballistica.net/cache/ba1/8a/32/2d21051d1323c399214ec09940af",
+ "assets/build/ba_data/audio/boxingBell.ogg": "https://files.ballistica.net/cache/ba1/86/ca/97324bed415f8d93bac5673c59a7",
+ "assets/build/ba_data/audio/bunny1.ogg": "https://files.ballistica.net/cache/ba1/c8/01/72b9ab237e862500919e125eb070",
+ "assets/build/ba_data/audio/bunny2.ogg": "https://files.ballistica.net/cache/ba1/4f/13/b14b19de434086a24b6204b92986",
+ "assets/build/ba_data/audio/bunny3.ogg": "https://files.ballistica.net/cache/ba1/6b/d0/b67594b5df5a88511a5aab5101a7",
+ "assets/build/ba_data/audio/bunny4.ogg": "https://files.ballistica.net/cache/ba1/11/a1/9bc6505aa0b34200a357ed1e46f4",
+ "assets/build/ba_data/audio/bunnyDeath.ogg": "https://files.ballistica.net/cache/ba1/54/d4/a1af8e4515f4cbb0d9d589848818",
+ "assets/build/ba_data/audio/bunnyFall.ogg": "https://files.ballistica.net/cache/ba1/cd/36/9d9f3c0bb0861f7604ca168d4a7e",
+ "assets/build/ba_data/audio/bunnyHit1.ogg": "https://files.ballistica.net/cache/ba1/41/26/61b7a43b0cd23687f815daf18c60",
+ "assets/build/ba_data/audio/bunnyHit2.ogg": "https://files.ballistica.net/cache/ba1/de/ad/0ccc9ae9dda0dfc9cc50dcfac3b4",
+ "assets/build/ba_data/audio/bunnyJump.ogg": "https://files.ballistica.net/cache/ba1/e5/3f/f7acab4718de4ff4f1ef376ba456",
+ "assets/build/ba_data/audio/cashRegister.ogg": "https://files.ballistica.net/cache/ba1/d2/eb/667f2ab1207a8e323c50c94ca4f0",
+ "assets/build/ba_data/audio/cashRegister2.ogg": "https://files.ballistica.net/cache/ba1/96/00/e2f56f515ca2ee86dc6a18583bad",
+ "assets/build/ba_data/audio/charSelectMusic.ogg": "https://files.ballistica.net/cache/ba1/0b/e5/86291ccda7ae68de644c5007b532",
+ "assets/build/ba_data/audio/cheer.ogg": "https://files.ballistica.net/cache/ba1/6f/8f/2f9d115bd2a51e6858b870e02b6a",
+ "assets/build/ba_data/audio/click01.ogg": "https://files.ballistica.net/cache/ba1/cf/80/188dee40c4dd4cc3fe578ee032b2",
+ "assets/build/ba_data/audio/corkPop.ogg": "https://files.ballistica.net/cache/ba1/b9/02/19bd057a40548c3b60eaf17c928c",
+ "assets/build/ba_data/audio/cowboy1.ogg": "https://files.ballistica.net/cache/ba1/68/8c/3373b19e185458a8d36a35c550b5",
+ "assets/build/ba_data/audio/cowboy2.ogg": "https://files.ballistica.net/cache/ba1/a3/d5/83ae98e99b36c1bba2851d38a5c6",
+ "assets/build/ba_data/audio/cowboy3.ogg": "https://files.ballistica.net/cache/ba1/75/31/325974b25d0cd7cbe8ef34db4604",
+ "assets/build/ba_data/audio/cowboy4.ogg": "https://files.ballistica.net/cache/ba1/70/60/506628ac2663fa636d6cc2ff0c9e",
+ "assets/build/ba_data/audio/cowboyDeath.ogg": "https://files.ballistica.net/cache/ba1/40/55/562bfacb5995609b30ddefc2d782",
+ "assets/build/ba_data/audio/cowboyFall.ogg": "https://files.ballistica.net/cache/ba1/26/13/ada14905566cd419c408128e97b2",
+ "assets/build/ba_data/audio/cowboyHit1.ogg": "https://files.ballistica.net/cache/ba1/0e/67/1516bfb2eda8d8b7de354bfa9d0b",
+ "assets/build/ba_data/audio/cowboyHit2.ogg": "https://files.ballistica.net/cache/ba1/55/a5/7a46ad9f88927fe0a177903a86ff",
+ "assets/build/ba_data/audio/crowdChant.ogg": "https://files.ballistica.net/cache/ba1/d8/6e/237f4cb04ae8461c4e889db7fa12",
+ "assets/build/ba_data/audio/cyborg1.ogg": "https://files.ballistica.net/cache/ba1/9a/1a/e5fd8e4ee4af08060674ce992597",
+ "assets/build/ba_data/audio/cyborg2.ogg": "https://files.ballistica.net/cache/ba1/45/e4/342ab3fe426e0aaba2914af83eb9",
+ "assets/build/ba_data/audio/cyborg3.ogg": "https://files.ballistica.net/cache/ba1/91/c4/3fc67797cd8df53c337cbab0c39b",
+ "assets/build/ba_data/audio/cyborg4.ogg": "https://files.ballistica.net/cache/ba1/7d/12/c8e0a38609e809cc1b4a6d862f93",
+ "assets/build/ba_data/audio/cyborgDeath.ogg": "https://files.ballistica.net/cache/ba1/b9/70/9fc1601bfd157fedb6805dedd4f4",
+ "assets/build/ba_data/audio/cyborgFall.ogg": "https://files.ballistica.net/cache/ba1/5a/fb/e446f768846de15fdba483778fec",
+ "assets/build/ba_data/audio/cyborgHit1.ogg": "https://files.ballistica.net/cache/ba1/be/b9/c37f719ed5f0a5eb6f781e710730",
+ "assets/build/ba_data/audio/cyborgHit2.ogg": "https://files.ballistica.net/cache/ba1/fb/50/cddc35fb924c329f34e66e364a79",
+ "assets/build/ba_data/audio/cymbal.ogg": "https://files.ballistica.net/cache/ba1/02/c5/c40782d2dc8af7486459f7562dae",
+ "assets/build/ba_data/audio/debrisFall.ogg": "https://files.ballistica.net/cache/ba1/48/f1/5f94e529c18182818e29c779ea7a",
+ "assets/build/ba_data/audio/deek.ogg": "https://files.ballistica.net/cache/ba1/26/55/e76b75a8976c6dbfa9e4ac33fa32",
+ "assets/build/ba_data/audio/deek2.ogg": "https://files.ballistica.net/cache/ba1/21/3c/519386c06338187db4664955c0f3",
+ "assets/build/ba_data/audio/ding.ogg": "https://files.ballistica.net/cache/ba1/86/6a/634899616fc81d3d085d0033d927",
+ "assets/build/ba_data/audio/dingSmall.ogg": "https://files.ballistica.net/cache/ba1/23/fe/aadabc5f5c2e6ffeefc8ed55a949",
+ "assets/build/ba_data/audio/dingSmallHigh.ogg": "https://files.ballistica.net/cache/ba1/77/91/feb963b876b7e6caa650c3ff3400",
+ "assets/build/ba_data/audio/dripity.ogg": "https://files.ballistica.net/cache/ba1/61/e7/29ee3bad420b6879edbf777a2d7c",
+ "assets/build/ba_data/audio/drumRoll.ogg": "https://files.ballistica.net/cache/ba1/7e/72/fbeaaaabab463ba158760ea1c7ae",
+ "assets/build/ba_data/audio/error.ogg": "https://files.ballistica.net/cache/ba1/84/0c/ee312556223bce6d097699774344",
+ "assets/build/ba_data/audio/explosion01.ogg": "https://files.ballistica.net/cache/ba1/0e/4b/3551c3e1700d3c6e6a3ebbd10181",
+ "assets/build/ba_data/audio/explosion02.ogg": "https://files.ballistica.net/cache/ba1/fa/16/1604023812cd6baca3899200f9df",
+ "assets/build/ba_data/audio/explosion03.ogg": "https://files.ballistica.net/cache/ba1/0b/5f/f35ff9788008d86a076792f0bcb2",
+ "assets/build/ba_data/audio/explosion04.ogg": "https://files.ballistica.net/cache/ba1/b8/2c/223871379c614d4faac3aa56ada9",
+ "assets/build/ba_data/audio/explosion05.ogg": "https://files.ballistica.net/cache/ba1/dc/cc/1cfdc45827d5268a1956a2c82cfe",
+ "assets/build/ba_data/audio/fanfare.ogg": "https://files.ballistica.net/cache/ba1/07/5b/f3df0050177a2c079be751476c40",
+ "assets/build/ba_data/audio/flagCatcherMusic.ogg": "https://files.ballistica.net/cache/ba1/2e/5b/7fe735133507cfd8caf66e79863d",
+ "assets/build/ba_data/audio/flyingMusic.ogg": "https://files.ballistica.net/cache/ba1/db/a9/b5388f5ead90edd58016f5b2b921",
+ "assets/build/ba_data/audio/foghorn.ogg": "https://files.ballistica.net/cache/ba1/99/47/9e7a4449483494b306daebf2ca6c",
+ "assets/build/ba_data/audio/footImpact01.ogg": "https://files.ballistica.net/cache/ba1/64/a3/6bfc5ed93444f9dff26ce99942e6",
+ "assets/build/ba_data/audio/footImpact02.ogg": "https://files.ballistica.net/cache/ba1/ba/aa/6edf42f5ba44faccc07d0e114471",
+ "assets/build/ba_data/audio/footImpact03.ogg": "https://files.ballistica.net/cache/ba1/08/ef/18968d63149d602158199f3817e3",
+ "assets/build/ba_data/audio/forwardMarchMusic.ogg": "https://files.ballistica.net/cache/ba1/54/de/1bb175851baf618e396c4406df1c",
+ "assets/build/ba_data/audio/freeze.ogg": "https://files.ballistica.net/cache/ba1/74/92/fd525f0d5856e31903c17b27c51a",
+ "assets/build/ba_data/audio/frosty01.ogg": "https://files.ballistica.net/cache/ba1/fd/1d/06797828ee496c9b9287b45becb1",
+ "assets/build/ba_data/audio/frosty02.ogg": "https://files.ballistica.net/cache/ba1/bb/1b/54b92409b7d92cddc7878f2e8fdc",
+ "assets/build/ba_data/audio/frosty03.ogg": "https://files.ballistica.net/cache/ba1/00/ae/f8d516a54e8efc2396f717110884",
+ "assets/build/ba_data/audio/frosty04.ogg": "https://files.ballistica.net/cache/ba1/67/1e/d06c47a926f602574501d9df4b4e",
+ "assets/build/ba_data/audio/frosty05.ogg": "https://files.ballistica.net/cache/ba1/22/b9/e32a718d13383201c4f5aaadbd52",
+ "assets/build/ba_data/audio/frostyDeath.ogg": "https://files.ballistica.net/cache/ba1/11/21/91d7beb3a9dda1bd4919c05f47d6",
+ "assets/build/ba_data/audio/frostyFall.ogg": "https://files.ballistica.net/cache/ba1/87/c1/3bd169f4d1e0d690fe66a67c1335",
+ "assets/build/ba_data/audio/frostyHit01.ogg": "https://files.ballistica.net/cache/ba1/f2/4c/69449f7a7667403e37b48440f674",
+ "assets/build/ba_data/audio/frostyHit02.ogg": "https://files.ballistica.net/cache/ba1/5a/b2/e06eea49faacd9047834faf0e8eb",
+ "assets/build/ba_data/audio/frostyHit03.ogg": "https://files.ballistica.net/cache/ba1/fa/c6/a07d169f2ba1ffcb029247ec0ae5",
+ "assets/build/ba_data/audio/fuse01.ogg": "https://files.ballistica.net/cache/ba1/7e/61/60e9ce59769a8bda0e365c9b79b5",
+ "assets/build/ba_data/audio/gladiator1.ogg": "https://files.ballistica.net/cache/ba1/88/c9/6c67ff6d678da2142f2a297437c3",
+ "assets/build/ba_data/audio/gladiator2.ogg": "https://files.ballistica.net/cache/ba1/4f/a7/b8a1261a11120869cfbc6d452498",
+ "assets/build/ba_data/audio/gladiator3.ogg": "https://files.ballistica.net/cache/ba1/b9/be/1fe5ae2c36ad998e61834deb4ccf",
+ "assets/build/ba_data/audio/gladiator4.ogg": "https://files.ballistica.net/cache/ba1/de/f8/6794201fb3677353e0f3c2a93611",
+ "assets/build/ba_data/audio/gladiatorDeath.ogg": "https://files.ballistica.net/cache/ba1/e9/19/4ff54749e7943d034cb8306636ab",
+ "assets/build/ba_data/audio/gladiatorFall.ogg": "https://files.ballistica.net/cache/ba1/00/f8/de4371b4d82c4221966045a881a9",
+ "assets/build/ba_data/audio/gladiatorHit1.ogg": "https://files.ballistica.net/cache/ba1/50/bf/a40c4350eaa5120cc0f8775eded6",
+ "assets/build/ba_data/audio/gladiatorHit2.ogg": "https://files.ballistica.net/cache/ba1/80/30/4374975d89173bbf9d6da8b6cbc1",
+ "assets/build/ba_data/audio/gong.ogg": "https://files.ballistica.net/cache/ba1/de/26/549acd4c51daea1c47f060fddb64",
+ "assets/build/ba_data/audio/grandRompMusic.ogg": "https://files.ballistica.net/cache/ba1/92/2c/16590cc58eeff0728fd2b06a4d23",
+ "assets/build/ba_data/audio/gravelSkid.ogg": "https://files.ballistica.net/cache/ba1/c7/1e/e26e96618299f5c5c2ac0e7502e5",
+ "assets/build/ba_data/audio/gunCocking.ogg": "https://files.ballistica.net/cache/ba1/8b/76/258f31e8817ecb64e30959fb05fb",
+ "assets/build/ba_data/audio/healthPowerup.ogg": "https://files.ballistica.net/cache/ba1/2a/c4/398c2d58cbcf8fb019a872df189d",
+ "assets/build/ba_data/audio/hiss.ogg": "https://files.ballistica.net/cache/ba1/bb/b8/764636c18e28b6fbc6f29e4fbb0a",
+ "assets/build/ba_data/audio/impactHard.ogg": "https://files.ballistica.net/cache/ba1/aa/f9/ff7036114170b2f49791fbda3f9f",
+ "assets/build/ba_data/audio/impactHard2.ogg": "https://files.ballistica.net/cache/ba1/48/2b/5c54dda49581c22569bd6a4b8099",
+ "assets/build/ba_data/audio/impactHard3.ogg": "https://files.ballistica.net/cache/ba1/4d/f8/1553be909395f694d54be4bb1a2c",
+ "assets/build/ba_data/audio/impactMedium.ogg": "https://files.ballistica.net/cache/ba1/39/bb/2f61284b7707f6158ec181d0002e",
+ "assets/build/ba_data/audio/impactMedium2.ogg": "https://files.ballistica.net/cache/ba1/2a/98/bdaf5d6f830ec0d513b1b3177084",
+ "assets/build/ba_data/audio/jack01.ogg": "https://files.ballistica.net/cache/ba1/1c/62/1c04cc46e16e6b1f1b02fc404c84",
+ "assets/build/ba_data/audio/jack02.ogg": "https://files.ballistica.net/cache/ba1/4e/0e/e27c72d96c91944ca820c094463e",
+ "assets/build/ba_data/audio/jack03.ogg": "https://files.ballistica.net/cache/ba1/3d/30/fa33b1cbefa6f6e3232e45303860",
+ "assets/build/ba_data/audio/jack04.ogg": "https://files.ballistica.net/cache/ba1/82/3e/06c311c35a9975ed4964b8d9b0ae",
+ "assets/build/ba_data/audio/jack05.ogg": "https://files.ballistica.net/cache/ba1/ce/c2/a7c55c9170f2927a08a8c8e8156c",
+ "assets/build/ba_data/audio/jack06.ogg": "https://files.ballistica.net/cache/ba1/c6/fc/39b003a695a7a072a37b7a1c0283",
+ "assets/build/ba_data/audio/jackDeath01.ogg": "https://files.ballistica.net/cache/ba1/08/32/217d3f04a56e186862690340be15",
+ "assets/build/ba_data/audio/jackFall01.ogg": "https://files.ballistica.net/cache/ba1/65/60/f52e44837a244a67675a81beb38f",
+ "assets/build/ba_data/audio/jackHit01.ogg": "https://files.ballistica.net/cache/ba1/37/23/eec4609886351cb5e40403d86606",
+ "assets/build/ba_data/audio/jackHit02.ogg": "https://files.ballistica.net/cache/ba1/c6/4f/004cc3e2f8a2a04921a27653a989",
+ "assets/build/ba_data/audio/jackHit03.ogg": "https://files.ballistica.net/cache/ba1/54/bd/dcaafa65dc58166bdfb694c29e30",
+ "assets/build/ba_data/audio/jackHit04.ogg": "https://files.ballistica.net/cache/ba1/26/74/cdbcda80829e53633bf24f8aad13",
+ "assets/build/ba_data/audio/jackHit05.ogg": "https://files.ballistica.net/cache/ba1/ce/a1/4b06286996288030d9a4c2024ecc",
+ "assets/build/ba_data/audio/jackHit06.ogg": "https://files.ballistica.net/cache/ba1/f3/aa/50a25629a99adad37b42060f5e83",
+ "assets/build/ba_data/audio/jackHit07.ogg": "https://files.ballistica.net/cache/ba1/94/3c/a1f1108481f6dd19b7cda3ede514",
+ "assets/build/ba_data/audio/jumpsuit1.ogg": "https://files.ballistica.net/cache/ba1/57/73/1dd98330e49d10c20a63a8e75f61",
+ "assets/build/ba_data/audio/jumpsuit2.ogg": "https://files.ballistica.net/cache/ba1/86/3b/4f2e67f2d6859fdf89168802f444",
+ "assets/build/ba_data/audio/jumpsuit3.ogg": "https://files.ballistica.net/cache/ba1/80/65/8f2ccf8e757f72d43dcd66e631d0",
+ "assets/build/ba_data/audio/jumpsuit4.ogg": "https://files.ballistica.net/cache/ba1/fa/70/4dde04a1fe8ab08ba1a9537cfa28",
+ "assets/build/ba_data/audio/jumpsuitDeath.ogg": "https://files.ballistica.net/cache/ba1/bc/76/3e07fac0798d90ae5fefd258ca7c",
+ "assets/build/ba_data/audio/jumpsuitFall.ogg": "https://files.ballistica.net/cache/ba1/c5/49/82d2744ce12253ac2067307eb510",
+ "assets/build/ba_data/audio/jumpsuitHit1.ogg": "https://files.ballistica.net/cache/ba1/31/c1/5d2a4c371b8aa8c34d1aa585fcc9",
+ "assets/build/ba_data/audio/jumpsuitHit2.ogg": "https://files.ballistica.net/cache/ba1/77/c4/2b10a6bc8c7272afcd11a06cac7f",
+ "assets/build/ba_data/audio/kronk1.ogg": "https://files.ballistica.net/cache/ba1/92/53/12382dfab3c9a0f57ee4ef1afb90",
+ "assets/build/ba_data/audio/kronk10.ogg": "https://files.ballistica.net/cache/ba1/7e/23/b04e1f29262b267e30c74aadc4b2",
+ "assets/build/ba_data/audio/kronk2.ogg": "https://files.ballistica.net/cache/ba1/1c/af/dafaf9923f8b214e88a8e4b33011",
+ "assets/build/ba_data/audio/kronk3.ogg": "https://files.ballistica.net/cache/ba1/e2/ac/21d6a67a98ba0182be220cfd9ebe",
+ "assets/build/ba_data/audio/kronk4.ogg": "https://files.ballistica.net/cache/ba1/cb/a0/42a3a76677a880e1a8ce0c964092",
+ "assets/build/ba_data/audio/kronk5.ogg": "https://files.ballistica.net/cache/ba1/40/8b/e2f13ab28ff82a4131d518fd41e5",
+ "assets/build/ba_data/audio/kronk6.ogg": "https://files.ballistica.net/cache/ba1/80/7c/ac6dc47f45fa9a000a0ca2d582f6",
+ "assets/build/ba_data/audio/kronk7.ogg": "https://files.ballistica.net/cache/ba1/70/16/e3feaa034fba214de90e880e9743",
+ "assets/build/ba_data/audio/kronk8.ogg": "https://files.ballistica.net/cache/ba1/8d/a0/c5157222123691d45353465f12d5",
+ "assets/build/ba_data/audio/kronk9.ogg": "https://files.ballistica.net/cache/ba1/27/75/d8444dc622c9b6962c5443341f79",
+ "assets/build/ba_data/audio/kronkDeath.ogg": "https://files.ballistica.net/cache/ba1/92/d6/578fcdd1ba905a7cefdd621b4ef6",
+ "assets/build/ba_data/audio/kronkFall.ogg": "https://files.ballistica.net/cache/ba1/02/9c/97fe8f1706508e10ad6b1162854e",
+ "assets/build/ba_data/audio/laser.ogg": "https://files.ballistica.net/cache/ba1/8a/7c/602971d0f2b05794020d32008f6a",
+ "assets/build/ba_data/audio/laserReverse.ogg": "https://files.ballistica.net/cache/ba1/b6/56/7e559691483ae0d885bc92cc36c5",
+ "assets/build/ba_data/audio/mel01.ogg": "https://files.ballistica.net/cache/ba1/3a/09/118fa673e3254433905352135c1c",
+ "assets/build/ba_data/audio/mel02.ogg": "https://files.ballistica.net/cache/ba1/7e/43/3392c6a5bb3885dd0de9b6232c50",
+ "assets/build/ba_data/audio/mel03.ogg": "https://files.ballistica.net/cache/ba1/a3/1c/9839c6a0e516481d3074036a45ba",
+ "assets/build/ba_data/audio/mel04.ogg": "https://files.ballistica.net/cache/ba1/be/2a/9d7f0cf15f42ea989ca27ebef6b6",
+ "assets/build/ba_data/audio/mel05.ogg": "https://files.ballistica.net/cache/ba1/a1/c1/b092017acab38c66a3ed55eaaf3b",
+ "assets/build/ba_data/audio/mel06.ogg": "https://files.ballistica.net/cache/ba1/ff/cc/7fd97dc8f8117e0cc7d38df94939",
+ "assets/build/ba_data/audio/mel07.ogg": "https://files.ballistica.net/cache/ba1/42/cf/e56f37f4645d6ca4d8fe9a7c3426",
+ "assets/build/ba_data/audio/mel08.ogg": "https://files.ballistica.net/cache/ba1/2e/dc/7f8a3f5acac99175b8a1ff58aa06",
+ "assets/build/ba_data/audio/mel09.ogg": "https://files.ballistica.net/cache/ba1/64/74/3eb12a075bcf1dfa9b0455db5dfc",
+ "assets/build/ba_data/audio/mel10.ogg": "https://files.ballistica.net/cache/ba1/8e/c0/32146bdb1479ad7444550d441f06",
+ "assets/build/ba_data/audio/melDeath01.ogg": "https://files.ballistica.net/cache/ba1/97/56/23a3ee374f0e473d096eb48abf8a",
+ "assets/build/ba_data/audio/melFall01.ogg": "https://files.ballistica.net/cache/ba1/85/a3/6e10c513e03bd80c66ae5981c9c2",
+ "assets/build/ba_data/audio/menuMusic.ogg": "https://files.ballistica.net/cache/ba1/cc/49/13383031864392995b3f625e9c9b",
+ "assets/build/ba_data/audio/metalHit.ogg": "https://files.ballistica.net/cache/ba1/2b/c3/0851274ba4e4dc47f51cc4540adf",
+ "assets/build/ba_data/audio/metalSkid.ogg": "https://files.ballistica.net/cache/ba1/db/e8/be77f30f6b6c884118af9f52a800",
+ "assets/build/ba_data/audio/ninjaAttack1.ogg": "https://files.ballistica.net/cache/ba1/94/e4/f0f32a8c1008592eb4bad00245bc",
+ "assets/build/ba_data/audio/ninjaAttack2.ogg": "https://files.ballistica.net/cache/ba1/fb/12/2cce5e7f25424280b7121102ee36",
+ "assets/build/ba_data/audio/ninjaAttack3.ogg": "https://files.ballistica.net/cache/ba1/a6/f6/17b84a8b2efdf271872fded73815",
+ "assets/build/ba_data/audio/ninjaAttack4.ogg": "https://files.ballistica.net/cache/ba1/bf/25/5c5c63c39a744810b4a7c9d7089a",
+ "assets/build/ba_data/audio/ninjaAttack5.ogg": "https://files.ballistica.net/cache/ba1/19/37/86f67ba3cfccdd8e8d30dc415fd0",
+ "assets/build/ba_data/audio/ninjaAttack6.ogg": "https://files.ballistica.net/cache/ba1/f6/58/ce731a7da821fd1138a0692ce7f7",
+ "assets/build/ba_data/audio/ninjaAttack7.ogg": "https://files.ballistica.net/cache/ba1/dd/b2/f0ec55e3f65a0a0fa8a1565a6d49",
+ "assets/build/ba_data/audio/ninjaDeath1.ogg": "https://files.ballistica.net/cache/ba1/17/1c/88b5859f42a5606090ededdf4bf7",
+ "assets/build/ba_data/audio/ninjaFall1.ogg": "https://files.ballistica.net/cache/ba1/bf/bc/ef6696a9dfb31af8badad6ee7fff",
+ "assets/build/ba_data/audio/ninjaHit1.ogg": "https://files.ballistica.net/cache/ba1/f9/bb/f476abe3b50eb8fcd3002df95b22",
+ "assets/build/ba_data/audio/ninjaHit2.ogg": "https://files.ballistica.net/cache/ba1/11/cc/911b8d4c993ebae870edcec86a46",
+ "assets/build/ba_data/audio/ninjaHit3.ogg": "https://files.ballistica.net/cache/ba1/bb/67/8a5953f01da909a145bd1a22470c",
+ "assets/build/ba_data/audio/ninjaHit4.ogg": "https://files.ballistica.net/cache/ba1/d1/c4/5aa44cf3d2c3b2044793c74b177b",
+ "assets/build/ba_data/audio/ninjaHit5.ogg": "https://files.ballistica.net/cache/ba1/eb/df/12b95eb8e0616deecaea628988bc",
+ "assets/build/ba_data/audio/ninjaHit6.ogg": "https://files.ballistica.net/cache/ba1/98/56/5308778fcaf1a8547109ea08a66a",
+ "assets/build/ba_data/audio/ninjaHit7.ogg": "https://files.ballistica.net/cache/ba1/08/89/61a0c888a516bf8e4ae7ae323af2",
+ "assets/build/ba_data/audio/ninjaHit8.ogg": "https://files.ballistica.net/cache/ba1/4e/87/b3034835560e227f62d469233dc4",
+ "assets/build/ba_data/audio/oldLady1.ogg": "https://files.ballistica.net/cache/ba1/23/b6/e583c9e55396baea7d441625692a",
+ "assets/build/ba_data/audio/oldLady2.ogg": "https://files.ballistica.net/cache/ba1/35/c2/dc9a508a69290ae6e263f0206b5c",
+ "assets/build/ba_data/audio/oldLady3.ogg": "https://files.ballistica.net/cache/ba1/71/ab/22e99664d2780c1ef20b65fad003",
+ "assets/build/ba_data/audio/oldLady4.ogg": "https://files.ballistica.net/cache/ba1/8a/82/83beaf3821e93e0fe736a3c30592",
+ "assets/build/ba_data/audio/oldLadyDeath.ogg": "https://files.ballistica.net/cache/ba1/6a/b9/346af6cff4c5748ea796b6abafed",
+ "assets/build/ba_data/audio/oldLadyFall.ogg": "https://files.ballistica.net/cache/ba1/c2/69/1310182b03601407132447127c14",
+ "assets/build/ba_data/audio/oldLadyHit1.ogg": "https://files.ballistica.net/cache/ba1/9c/24/c8df1677d02c892a0c74f193cc58",
+ "assets/build/ba_data/audio/oldLadyHit2.ogg": "https://files.ballistica.net/cache/ba1/86/42/b78059df876aeeba7cde76f347d5",
+ "assets/build/ba_data/audio/ooh.ogg": "https://files.ballistica.net/cache/ba1/25/86/00dceb798bec698d564fb880d288",
+ "assets/build/ba_data/audio/operaSinger1.ogg": "https://files.ballistica.net/cache/ba1/e6/15/c5b4926b51c2eb04ab223c2d01eb",
+ "assets/build/ba_data/audio/operaSinger2.ogg": "https://files.ballistica.net/cache/ba1/d5/d6/a0478ff5e3804996ced4d6de7143",
+ "assets/build/ba_data/audio/operaSinger3.ogg": "https://files.ballistica.net/cache/ba1/37/55/796b2fac352d99e2422efc5cebe2",
+ "assets/build/ba_data/audio/operaSinger4.ogg": "https://files.ballistica.net/cache/ba1/d4/a5/c14bebda9a7193648f0f78287c0d",
+ "assets/build/ba_data/audio/operaSingerDeath.ogg": "https://files.ballistica.net/cache/ba1/a6/e0/7062e26e6193137ed02ff70f4095",
+ "assets/build/ba_data/audio/operaSingerFall.ogg": "https://files.ballistica.net/cache/ba1/55/02/5d2b94bcabc95eeba9fabb3c8da4",
+ "assets/build/ba_data/audio/operaSingerHit1.ogg": "https://files.ballistica.net/cache/ba1/71/8e/4d7a40c3d3e1f280b6ecaefde7fc",
+ "assets/build/ba_data/audio/operaSingerHit2.ogg": "https://files.ballistica.net/cache/ba1/8c/ce/bb1399951b84401320ce2415f216",
+ "assets/build/ba_data/audio/orchestraHit.ogg": "https://files.ballistica.net/cache/ba1/f7/40/e55b676563eb8b73dadc680f4087",
+ "assets/build/ba_data/audio/orchestraHit2.ogg": "https://files.ballistica.net/cache/ba1/31/01/922ae1bee4bd708fb5303a011649",
+ "assets/build/ba_data/audio/orchestraHit3.ogg": "https://files.ballistica.net/cache/ba1/5a/c7/4ae69a081deb0f15ccc4d80955ad",
+ "assets/build/ba_data/audio/orchestraHit4.ogg": "https://files.ballistica.net/cache/ba1/2e/9a/cb8851c3b2798f3f67db6d62f0aa",
+ "assets/build/ba_data/audio/orchestraHitBig1.ogg": "https://files.ballistica.net/cache/ba1/8d/d8/179398fd62a92ecd3bcc9a73320d",
+ "assets/build/ba_data/audio/orchestraHitBig2.ogg": "https://files.ballistica.net/cache/ba1/55/9c/2c8c26f97e27ac28795e9366a487",
+ "assets/build/ba_data/audio/penguin1.ogg": "https://files.ballistica.net/cache/ba1/94/00/730934565bd430fde432ec107fac",
+ "assets/build/ba_data/audio/penguin2.ogg": "https://files.ballistica.net/cache/ba1/8d/2c/742ca54b4540200ecb0ec6630ceb",
+ "assets/build/ba_data/audio/penguin3.ogg": "https://files.ballistica.net/cache/ba1/50/a8/629e1a962b7632b3d206e32df573",
+ "assets/build/ba_data/audio/penguin4.ogg": "https://files.ballistica.net/cache/ba1/9e/7f/4ae04352ccca806a8db848a3fdc7",
+ "assets/build/ba_data/audio/penguinDeath.ogg": "https://files.ballistica.net/cache/ba1/1e/ee/5df67de9720d116af405fe7229e0",
+ "assets/build/ba_data/audio/penguinFall.ogg": "https://files.ballistica.net/cache/ba1/06/5d/21d5a6a788ac893c295fbcff3c79",
+ "assets/build/ba_data/audio/penguinHit1.ogg": "https://files.ballistica.net/cache/ba1/35/bb/1bdc39ff4050e0b1a6d3f440a619",
+ "assets/build/ba_data/audio/penguinHit2.ogg": "https://files.ballistica.net/cache/ba1/f6/5d/8a64472b98182d5b30f0d6a940bb",
+ "assets/build/ba_data/audio/pixie1.ogg": "https://files.ballistica.net/cache/ba1/05/76/fa2b4a792f863720c95334ae3824",
+ "assets/build/ba_data/audio/pixie2.ogg": "https://files.ballistica.net/cache/ba1/fa/50/44c1f6bbd185bb3b6075a1e17f24",
+ "assets/build/ba_data/audio/pixie3.ogg": "https://files.ballistica.net/cache/ba1/25/db/7e63097cc2f123d1cc1f6a504e30",
+ "assets/build/ba_data/audio/pixie4.ogg": "https://files.ballistica.net/cache/ba1/23/0e/7089a6dd3077595da4dcfbe6565b",
+ "assets/build/ba_data/audio/pixieDeath.ogg": "https://files.ballistica.net/cache/ba1/71/83/f4c744d6d4f4cf22ef618ee98997",
+ "assets/build/ba_data/audio/pixieFall.ogg": "https://files.ballistica.net/cache/ba1/6d/0b/47a2e5e9f03c58b42b204a435458",
+ "assets/build/ba_data/audio/pixieHit1.ogg": "https://files.ballistica.net/cache/ba1/de/83/3415d2b244b7a3b902a4970416cc",
+ "assets/build/ba_data/audio/pixieHit2.ogg": "https://files.ballistica.net/cache/ba1/77/f5/df2a4f2d085fc5fbc5118aac6cdf",
+ "assets/build/ba_data/audio/playerDeath.ogg": "https://files.ballistica.net/cache/ba1/6a/54/5043aff36f18c30bcd05eb674027",
+ "assets/build/ba_data/audio/playerLeft.ogg": "https://files.ballistica.net/cache/ba1/2e/ec/05255f5178d4f2164941ce181693",
+ "assets/build/ba_data/audio/pop01.ogg": "https://files.ballistica.net/cache/ba1/83/06/b414e78ce2728857961a1fafc776",
+ "assets/build/ba_data/audio/powerdown01.ogg": "https://files.ballistica.net/cache/ba1/f6/e9/e76b20df199c29b25acb9e9b2900",
+ "assets/build/ba_data/audio/powerup01.ogg": "https://files.ballistica.net/cache/ba1/e4/11/5d617fb6618f66e7583118d61121",
+ "assets/build/ba_data/audio/punch01.ogg": "https://files.ballistica.net/cache/ba1/a9/00/c9a15783ee6cfc06e947f0a48838",
+ "assets/build/ba_data/audio/punchStrong01.ogg": "https://files.ballistica.net/cache/ba1/2a/74/3ec262182bf47e32a2e532772f04",
+ "assets/build/ba_data/audio/punchStrong02.ogg": "https://files.ballistica.net/cache/ba1/d8/32/ec4a0222196c0d37e7fa39c4f8e9",
+ "assets/build/ba_data/audio/punchSwish.ogg": "https://files.ballistica.net/cache/ba1/20/4d/56a407153984e49f5f8afd69355b",
+ "assets/build/ba_data/audio/punchWeak01.ogg": "https://files.ballistica.net/cache/ba1/a7/9a/926e43376c60d8f2a4649d0fc69a",
+ "assets/build/ba_data/audio/raceBeep1.ogg": "https://files.ballistica.net/cache/ba1/fc/47/a764a773a46529dd93949630dcca",
+ "assets/build/ba_data/audio/raceBeep2.ogg": "https://files.ballistica.net/cache/ba1/40/03/b9669de98d51bb2470c65e5ef5bb",
+ "assets/build/ba_data/audio/refWhistle.ogg": "https://files.ballistica.net/cache/ba1/22/4c/87b961b27f2aa34da0f68f0fc92f",
+ "assets/build/ba_data/audio/robot1.ogg": "https://files.ballistica.net/cache/ba1/a9/bb/e87b221e6c3ec6072abd77042f34",
+ "assets/build/ba_data/audio/robot2.ogg": "https://files.ballistica.net/cache/ba1/8d/39/1087553e71d32cdd47603df963e1",
+ "assets/build/ba_data/audio/robot3.ogg": "https://files.ballistica.net/cache/ba1/65/cc/f942367aba3991610ae44d178d17",
+ "assets/build/ba_data/audio/robot4.ogg": "https://files.ballistica.net/cache/ba1/39/d7/d86221ff9da5dc105d2bfee2f9c1",
+ "assets/build/ba_data/audio/robotDeath.ogg": "https://files.ballistica.net/cache/ba1/07/8e/293a3691c4a7bfc5e651c31bd65a",
+ "assets/build/ba_data/audio/robotFall.ogg": "https://files.ballistica.net/cache/ba1/fb/f5/096a2f5fd352c5b5f85322385553",
+ "assets/build/ba_data/audio/robotHit1.ogg": "https://files.ballistica.net/cache/ba1/bf/0b/d91f57170f990f7888d09284690f",
+ "assets/build/ba_data/audio/robotHit2.ogg": "https://files.ballistica.net/cache/ba1/b3/a0/6d0d855cc5f6dec007f8ba2d810f",
+ "assets/build/ba_data/audio/runAwayMusic.ogg": "https://files.ballistica.net/cache/ba1/8c/c2/971e087565455a2ce80e47ed6658",
+ "assets/build/ba_data/audio/santa01.ogg": "https://files.ballistica.net/cache/ba1/b3/b9/07700a0883f8ee4c12279a81b60b",
+ "assets/build/ba_data/audio/santa02.ogg": "https://files.ballistica.net/cache/ba1/57/d2/8665eca3efa556755642f88d5aac",
+ "assets/build/ba_data/audio/santa03.ogg": "https://files.ballistica.net/cache/ba1/53/4f/5088324716833ee239d7722ea560",
+ "assets/build/ba_data/audio/santa04.ogg": "https://files.ballistica.net/cache/ba1/87/52/d8b8fcc377ea66d0b47566567d85",
+ "assets/build/ba_data/audio/santa05.ogg": "https://files.ballistica.net/cache/ba1/f3/31/08d8ba4eae522c801be0190948d7",
+ "assets/build/ba_data/audio/santaDeath.ogg": "https://files.ballistica.net/cache/ba1/a8/9b/f144aa380a91d073308c3d3b9b8e",
+ "assets/build/ba_data/audio/santaFall.ogg": "https://files.ballistica.net/cache/ba1/ee/b5/74bd7718bbcee351a645495eb58a",
+ "assets/build/ba_data/audio/santaHit01.ogg": "https://files.ballistica.net/cache/ba1/bb/a1/63789e19dac322aa6e0f5f61ad67",
+ "assets/build/ba_data/audio/santaHit02.ogg": "https://files.ballistica.net/cache/ba1/5b/8e/878f173b2ec476f0ad3d82ff5774",
+ "assets/build/ba_data/audio/santaHit03.ogg": "https://files.ballistica.net/cache/ba1/3d/c9/90e1e0b8c35d3fa76b6e328b7f54",
+ "assets/build/ba_data/audio/santaHit04.ogg": "https://files.ballistica.net/cache/ba1/d5/52/049cb508fe82c93a7d663b90f0b1",
+ "assets/build/ba_data/audio/scamper01.ogg": "https://files.ballistica.net/cache/ba1/f5/b3/5b83270ad3201b7d61b5b93bb629",
+ "assets/build/ba_data/audio/scaryMusic.ogg": "https://files.ballistica.net/cache/ba1/1e/cf/be2c3d100aeae6d92b1fb3ac5d18",
+ "assets/build/ba_data/audio/score.ogg": "https://files.ballistica.net/cache/ba1/bd/82/ea9f18f10f816353c242f0ecea06",
+ "assets/build/ba_data/audio/scoreHit01.ogg": "https://files.ballistica.net/cache/ba1/13/a8/1352a2ca591fe2b64ea4bcc88819",
+ "assets/build/ba_data/audio/scoreHit02.ogg": "https://files.ballistica.net/cache/ba1/74/a8/e85986c5c798b1d16f8da6176ce0",
+ "assets/build/ba_data/audio/scoreIncrease.ogg": "https://files.ballistica.net/cache/ba1/54/6c/50da3039336a99bbffcbfe20b26d",
+ "assets/build/ba_data/audio/scoresEpicMusic.ogg": "https://files.ballistica.net/cache/ba1/29/da/79c1aa23e27e9c9abc20431d5a56",
+ "assets/build/ba_data/audio/shatter.ogg": "https://files.ballistica.net/cache/ba1/0d/d4/00dea0214b677caa2ad90fcb8f48",
+ "assets/build/ba_data/audio/shieldDown.ogg": "https://files.ballistica.net/cache/ba1/29/bd/170f71f2bbcf76079a6cccaa273e",
+ "assets/build/ba_data/audio/shieldHit.ogg": "https://files.ballistica.net/cache/ba1/aa/c2/cccb76ea873b76eb76a1aa1e8c77",
+ "assets/build/ba_data/audio/shieldUp.ogg": "https://files.ballistica.net/cache/ba1/ac/e8/6545cb9e9fba040e97621fe4f6bc",
+ "assets/build/ba_data/audio/skid01.ogg": "https://files.ballistica.net/cache/ba1/95/dc/66f20db82fbfea99c4a688fad27c",
+ "assets/build/ba_data/audio/slowEpicMusic.ogg": "https://files.ballistica.net/cache/ba1/f4/60/8981aea1b5b59f877ec842961790",
+ "assets/build/ba_data/audio/sparkle01.ogg": "https://files.ballistica.net/cache/ba1/63/24/2eaa301b8b6eaed9ec061087db75",
+ "assets/build/ba_data/audio/sparkle02.ogg": "https://files.ballistica.net/cache/ba1/e6/b4/d8f7db36cad567c64d3c8e5a75e2",
+ "assets/build/ba_data/audio/sparkle03.ogg": "https://files.ballistica.net/cache/ba1/59/a3/cfa33be130080d31f821ed5fc15c",
+ "assets/build/ba_data/audio/spawn.ogg": "https://files.ballistica.net/cache/ba1/dc/db/ffc5dbfe9020f8fc1baa1627bf98",
+ "assets/build/ba_data/audio/spazAttack01.ogg": "https://files.ballistica.net/cache/ba1/40/21/dad4e34fbbadb39862f63e48ac7c",
+ "assets/build/ba_data/audio/spazAttack02.ogg": "https://files.ballistica.net/cache/ba1/d4/fd/61c426c86c6c296a24ced82ad12c",
+ "assets/build/ba_data/audio/spazAttack03.ogg": "https://files.ballistica.net/cache/ba1/26/c4/46ab01345c4e7e9dcfc0be64ff64",
+ "assets/build/ba_data/audio/spazAttack04.ogg": "https://files.ballistica.net/cache/ba1/51/b6/860b82afe412a6adeb980a4f8bd5",
+ "assets/build/ba_data/audio/spazDeath01.ogg": "https://files.ballistica.net/cache/ba1/73/7c/46a4e6e6e2c3aa39d4e81e3a716d",
+ "assets/build/ba_data/audio/spazEff.ogg": "https://files.ballistica.net/cache/ba1/35/88/be365b45893740e697576cdb294a",
+ "assets/build/ba_data/audio/spazFall01.ogg": "https://files.ballistica.net/cache/ba1/21/d4/d9c29261db4c42c9f5ac5c7eb950",
+ "assets/build/ba_data/audio/spazImpact01.ogg": "https://files.ballistica.net/cache/ba1/07/72/8ab23dbfbf371404db23e6722f82",
+ "assets/build/ba_data/audio/spazImpact02.ogg": "https://files.ballistica.net/cache/ba1/03/b2/2cc5b6e0d1d715146ed0f888fa59",
+ "assets/build/ba_data/audio/spazImpact03.ogg": "https://files.ballistica.net/cache/ba1/52/30/08fb7e63cd27351740769d79d626",
+ "assets/build/ba_data/audio/spazImpact04.ogg": "https://files.ballistica.net/cache/ba1/0f/3c/2a7827864bb30906fa81bed522f7",
+ "assets/build/ba_data/audio/spazJump01.ogg": "https://files.ballistica.net/cache/ba1/21/0e/f8b7b96c4791a9f1c80c98fb12c2",
+ "assets/build/ba_data/audio/spazJump02.ogg": "https://files.ballistica.net/cache/ba1/71/dd/7d0d9847c3925f8735caabd16170",
+ "assets/build/ba_data/audio/spazJump03.ogg": "https://files.ballistica.net/cache/ba1/99/f8/4eca4d27afdcaf063b131ba26f66",
+ "assets/build/ba_data/audio/spazJump04.ogg": "https://files.ballistica.net/cache/ba1/21/1e/0b3c481d59510611c4860f27c7f8",
+ "assets/build/ba_data/audio/spazOw.ogg": "https://files.ballistica.net/cache/ba1/12/18/6db0e1f777e931e090b669cd32a7",
+ "assets/build/ba_data/audio/spazPickup01.ogg": "https://files.ballistica.net/cache/ba1/5c/39/f6a46cb0701d8577089292c0763c",
+ "assets/build/ba_data/audio/spazScream01.ogg": "https://files.ballistica.net/cache/ba1/4b/3e/80324014a068b4860b942e97c000",
+ "assets/build/ba_data/audio/splatter.ogg": "https://files.ballistica.net/cache/ba1/e8/10/4396d70a2dea20dcccb5bf5938f4",
+ "assets/build/ba_data/audio/sportsMusic.ogg": "https://files.ballistica.net/cache/ba1/e2/ec/83a0972daeca225baee5a96f4d0f",
+ "assets/build/ba_data/audio/stickyImpact.ogg": "https://files.ballistica.net/cache/ba1/e6/dc/e50bdd128233ecb205169f47a06f",
+ "assets/build/ba_data/audio/superPunch.ogg": "https://files.ballistica.net/cache/ba1/cc/fb/cc67aae917024b2ea0d19e7da970",
+ "assets/build/ba_data/audio/superhero1.ogg": "https://files.ballistica.net/cache/ba1/46/d8/bd217faa30cfd48d244ef6fc6fc2",
+ "assets/build/ba_data/audio/superhero2.ogg": "https://files.ballistica.net/cache/ba1/d6/73/aa54800eee58d7d82cc323e88ef2",
+ "assets/build/ba_data/audio/superhero3.ogg": "https://files.ballistica.net/cache/ba1/ba/fa/27e127906e41a9342da5ff5a9fff",
+ "assets/build/ba_data/audio/superhero4.ogg": "https://files.ballistica.net/cache/ba1/3d/9e/0e8a39bb98efbce06a02e0c39e08",
+ "assets/build/ba_data/audio/superheroDeath.ogg": "https://files.ballistica.net/cache/ba1/4d/c9/54f96f1fb064986dfc078fa7d153",
+ "assets/build/ba_data/audio/superheroFall.ogg": "https://files.ballistica.net/cache/ba1/f7/c1/7f7fe02bc478f31566c0d02aeaf9",
+ "assets/build/ba_data/audio/superheroHit1.ogg": "https://files.ballistica.net/cache/ba1/35/dc/ac39f0b3858505d84fa80481883d",
+ "assets/build/ba_data/audio/superheroHit2.ogg": "https://files.ballistica.net/cache/ba1/09/74/11ef7365f7e948c7295fde1deabf",
+ "assets/build/ba_data/audio/survivalMusic.ogg": "https://files.ballistica.net/cache/ba1/f0/b2/40fb3eb2f68230dd5bd9bb23abca",
+ "assets/build/ba_data/audio/swip.ogg": "https://files.ballistica.net/cache/ba1/75/c3/09daac42c93fd4170906277ae08d",
+ "assets/build/ba_data/audio/swip2.ogg": "https://files.ballistica.net/cache/ba1/d5/0e/1b2987a3df94c5a8da7de53b30b0",
+ "assets/build/ba_data/audio/swish.ogg": "https://files.ballistica.net/cache/ba1/b5/50/6d96f9c731eece1f41d5067162ec",
+ "assets/build/ba_data/audio/swish2.ogg": "https://files.ballistica.net/cache/ba1/89/e7/1d30d1f757e92ee55042c8d9ce2b",
+ "assets/build/ba_data/audio/swish3.ogg": "https://files.ballistica.net/cache/ba1/f3/b6/1c5765c45c406ebd639297d847b7",
+ "assets/build/ba_data/audio/tap.ogg": "https://files.ballistica.net/cache/ba1/d0/35/dcbcf86733c3ce21df2e09166710",
+ "assets/build/ba_data/audio/technoHit01.ogg": "https://files.ballistica.net/cache/ba1/82/ea/e84c6e3d280b87f4c5cc8f9fdfc2",
+ "assets/build/ba_data/audio/tick.ogg": "https://files.ballistica.net/cache/ba1/1e/63/802a48d047f15162ca3f7861504b",
+ "assets/build/ba_data/audio/ticking.ogg": "https://files.ballistica.net/cache/ba1/7a/84/33fb89ab3f262ab8bb378a03402b",
+ "assets/build/ba_data/audio/tickingCrazy.ogg": "https://files.ballistica.net/cache/ba1/b1/96/14f02de4aad3d1d51b38f6f1b343",
+ "assets/build/ba_data/audio/toTheDeathMusic.ogg": "https://files.ballistica.net/cache/ba1/6b/2c/8cc2e93b42cf09465c03ef07234e",
+ "assets/build/ba_data/audio/trashRummage.ogg": "https://files.ballistica.net/cache/ba1/23/32/e4031e376a063bc205e15b392395",
+ "assets/build/ba_data/audio/victoryMusic.ogg": "https://files.ballistica.net/cache/ba1/84/d5/8f8bf8269d36ac4dbebec89159dd",
+ "assets/build/ba_data/audio/warnBeep.ogg": "https://files.ballistica.net/cache/ba1/6e/c5/d9e4b56ae4926b50e12a3a2e6036",
+ "assets/build/ba_data/audio/warnBeeps.ogg": "https://files.ballistica.net/cache/ba1/a2/93/f95d3347840177b078102c0a4028",
+ "assets/build/ba_data/audio/warrior1.ogg": "https://files.ballistica.net/cache/ba1/17/ca/48f76a70469d63265a5978a05128",
+ "assets/build/ba_data/audio/warrior2.ogg": "https://files.ballistica.net/cache/ba1/2e/73/6ee946fc42aea8ae27a2e3c7dd5c",
+ "assets/build/ba_data/audio/warrior3.ogg": "https://files.ballistica.net/cache/ba1/db/e6/0af15fc533f7292cd6b62f2c36e9",
+ "assets/build/ba_data/audio/warrior4.ogg": "https://files.ballistica.net/cache/ba1/83/4e/8e321701e3dfa1d14ecf1f92ed02",
+ "assets/build/ba_data/audio/warriorDeath.ogg": "https://files.ballistica.net/cache/ba1/87/70/f6ad5485cceccf40233240b2a7ca",
+ "assets/build/ba_data/audio/warriorFall.ogg": "https://files.ballistica.net/cache/ba1/6b/b8/b48e3a7ed8085c37eb69035e529f",
+ "assets/build/ba_data/audio/warriorHit1.ogg": "https://files.ballistica.net/cache/ba1/81/40/8578d5ffbbfe59acfc49c27f40bf",
+ "assets/build/ba_data/audio/warriorHit2.ogg": "https://files.ballistica.net/cache/ba1/a0/a2/2e30e4bc356af477bab1573e5570",
+ "assets/build/ba_data/audio/whenJohnnyComesMarchingHomeMusic.ogg": "https://files.ballistica.net/cache/ba1/91/65/57cada2658f28e706933e4110647",
+ "assets/build/ba_data/audio/witch1.ogg": "https://files.ballistica.net/cache/ba1/ce/72/20c761164d060605e9028c986d5c",
+ "assets/build/ba_data/audio/witch2.ogg": "https://files.ballistica.net/cache/ba1/8c/16/4df9cd932d1efa6fed6b2a5c540b",
+ "assets/build/ba_data/audio/witch3.ogg": "https://files.ballistica.net/cache/ba1/e2/3d/cef854cdf47cd38c8aea08166295",
+ "assets/build/ba_data/audio/witch4.ogg": "https://files.ballistica.net/cache/ba1/ce/c1/58f794dbbd62f99edd1ced17944a",
+ "assets/build/ba_data/audio/witchDeath.ogg": "https://files.ballistica.net/cache/ba1/51/d8/7c34335d3823fbbb4300524de2ef",
+ "assets/build/ba_data/audio/witchFall.ogg": "https://files.ballistica.net/cache/ba1/80/71/361cd5835b2ef5e94b88b169e9d9",
+ "assets/build/ba_data/audio/witchHit1.ogg": "https://files.ballistica.net/cache/ba1/78/64/061ce2c10572a4e12a4053d6bbe4",
+ "assets/build/ba_data/audio/witchHit2.ogg": "https://files.ballistica.net/cache/ba1/17/18/d10d17e5e6fbba5ff0603f6d7017",
+ "assets/build/ba_data/audio/wizard1.ogg": "https://files.ballistica.net/cache/ba1/4f/17/5ba31bd06ee640f9852a27c60f31",
+ "assets/build/ba_data/audio/wizard2.ogg": "https://files.ballistica.net/cache/ba1/f7/19/ae64da8e46abaa4ea9f2c0bc370b",
+ "assets/build/ba_data/audio/wizard3.ogg": "https://files.ballistica.net/cache/ba1/dd/0e/fa4d92c7dd2f0e9acb9002ff801a",
+ "assets/build/ba_data/audio/wizard4.ogg": "https://files.ballistica.net/cache/ba1/1b/15/fc7242232699d32f0639b04f2438",
+ "assets/build/ba_data/audio/wizardDeath.ogg": "https://files.ballistica.net/cache/ba1/83/46/ec91700389f7374da9e37dd6ce68",
+ "assets/build/ba_data/audio/wizardFall.ogg": "https://files.ballistica.net/cache/ba1/0a/b2/18d65c8844b99469dc1985ecc1c0",
+ "assets/build/ba_data/audio/wizardHit1.ogg": "https://files.ballistica.net/cache/ba1/ee/f6/b1c0be492c0b94247227d9e2e208",
+ "assets/build/ba_data/audio/wizardHit2.ogg": "https://files.ballistica.net/cache/ba1/7f/35/5d78c61d24aece5034b875d33915",
+ "assets/build/ba_data/audio/woodDebrisFall.ogg": "https://files.ballistica.net/cache/ba1/19/6e/c9ae199861928cf055f65bfd41c1",
+ "assets/build/ba_data/audio/wrestler1.ogg": "https://files.ballistica.net/cache/ba1/65/12/75cdf8b3c6e2cfa449af2bd48d28",
+ "assets/build/ba_data/audio/wrestler2.ogg": "https://files.ballistica.net/cache/ba1/cb/93/68ca08277b2cc4c1c50285cfc3a1",
+ "assets/build/ba_data/audio/wrestler3.ogg": "https://files.ballistica.net/cache/ba1/a8/46/187725de20d48fdb74a3fd9f2846",
+ "assets/build/ba_data/audio/wrestler4.ogg": "https://files.ballistica.net/cache/ba1/83/2f/8d5b804233b998b45951a20b8fdb",
+ "assets/build/ba_data/audio/wrestlerDeath.ogg": "https://files.ballistica.net/cache/ba1/1b/05/f3368eb8ff53ab21f7bbfc342bcf",
+ "assets/build/ba_data/audio/wrestlerFall.ogg": "https://files.ballistica.net/cache/ba1/f3/60/45e99d33dfaf8a54094ed6959a76",
+ "assets/build/ba_data/audio/wrestlerHit1.ogg": "https://files.ballistica.net/cache/ba1/7b/29/60fb951efa48006ea6b3c96b739d",
+ "assets/build/ba_data/audio/wrestlerHit2.ogg": "https://files.ballistica.net/cache/ba1/ef/8c/8f007cd6557b5ae4a3f59e8bc688",
+ "assets/build/ba_data/audio/zoeAttack01.ogg": "https://files.ballistica.net/cache/ba1/dc/a6/971dc4a19c5c7c918030314e5e65",
+ "assets/build/ba_data/audio/zoeAttack02.ogg": "https://files.ballistica.net/cache/ba1/d9/32/5a0e67d1103221c7a7e0aa788f42",
+ "assets/build/ba_data/audio/zoeAttack03.ogg": "https://files.ballistica.net/cache/ba1/ef/ce/7b589e1c5819225e21806381e0f8",
+ "assets/build/ba_data/audio/zoeAttack04.ogg": "https://files.ballistica.net/cache/ba1/6e/80/afaf8327c04b2ebc3bb5725f2bb3",
+ "assets/build/ba_data/audio/zoeDeath01.ogg": "https://files.ballistica.net/cache/ba1/46/89/29cc9dd73247c6cc7c3cdfd0e3fc",
+ "assets/build/ba_data/audio/zoeEff.ogg": "https://files.ballistica.net/cache/ba1/3c/fc/9a88a182782657a2f3915188d07c",
+ "assets/build/ba_data/audio/zoeFall01.ogg": "https://files.ballistica.net/cache/ba1/d5/12/be8a9e8ab228aabb508e7d003252",
+ "assets/build/ba_data/audio/zoeImpact01.ogg": "https://files.ballistica.net/cache/ba1/0c/67/c3f8fafce3b164449fa5bd9250b8",
+ "assets/build/ba_data/audio/zoeImpact02.ogg": "https://files.ballistica.net/cache/ba1/c2/15/6b5702466d1322c181a5b5fcd7f1",
+ "assets/build/ba_data/audio/zoeImpact03.ogg": "https://files.ballistica.net/cache/ba1/c1/0c/6e4ff9a5ad7b190f894576296365",
+ "assets/build/ba_data/audio/zoeImpact04.ogg": "https://files.ballistica.net/cache/ba1/82/bb/cbd7dccc559b5687d54419fcaece",
+ "assets/build/ba_data/audio/zoeJump01.ogg": "https://files.ballistica.net/cache/ba1/55/11/f672f83dd6648e34993d14c02090",
+ "assets/build/ba_data/audio/zoeJump02.ogg": "https://files.ballistica.net/cache/ba1/93/0a/6199fd614fc14e164d2c7b466468",
+ "assets/build/ba_data/audio/zoeJump03.ogg": "https://files.ballistica.net/cache/ba1/11/0f/acaa3ae6c450b20da990df107f0d",
+ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/a9/71/9286d55c45c37877f3267850f90b",
+ "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/2f/09/36e691de67eb8f155449a7170861",
+ "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/fd/a8/ad50785ce206e8dc3dcc7358b173",
+ "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d3/ac/c9ea9fa822efd364afa707011ed7",
+ "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/ac/3e/c50dc4e98df47f858c3a73ac4272",
+ "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/44/ed/5b972fa848cffb73723533c2ccb7",
+ "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/9d/63/d360eeff63bc64e098427498880d",
+ "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/87/d3/c522210fd993c71d364eed3ed314",
+ "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/66/bf/6e98398016da261296b8c306560e",
+ "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/e3/10/ace3a73616f1f36540e585e5bbce",
"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/86/33/8400929a710ae4a90f3f7cb57518",
- "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/94/bb/79fd4608f4a3e22526442ba77090",
+ "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/66/d1/8adfe1479fe6b4c30cd0d0e694d6",
"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/b4/35/4860ac0f2f30881221b5545560ce",
- "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/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/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/68/c1/7bdfe775a89273d30f67c98689bf",
- "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/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/5e/97/5e3a1d4de8a7c2b062c8cd84c99a",
- "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/1c/0f/ff64ff97ee5244a6d6c1a24fb4e3",
+ "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/41/30/040a5038fccbfeaa28e85d3bc863",
+ "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/bc/62/e8a3da4b4c09841edade01c5c921",
+ "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/43/f3/9e88a199337b7913cb5e7961b1c6",
+ "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/51/31/64479524c0ee990b3e97ffdca068",
+ "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/32/a4/fae7a30ead18c6cb97db60dd9445",
+ "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/69/cf/4a1e297b73613fd1b87fed8d2565",
+ "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/fb/2b/4c875a40e176079dedaacf1362c7",
+ "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/78/d3/16b37707d4ce4df826d0b0bc1766",
+ "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c1/14/b013ec0a6557533f0ff49f27d000",
+ "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/cd/c1/82bf70c3ee4894791506f4da1a15",
+ "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/98/45/ddeb7e797c02fb967e0c8b0dff7d",
+ "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f3/e5/c6d8fab0509451976c776265f0d0",
+ "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/71/db/e23447c97d40b8a0d83f185f4bba",
+ "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e1/22/5471375791f8825a63e06371df29",
+ "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/15/01/cab2f74365e69216a7eeeef51f98",
+ "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/bd/be/7bf759c649d8a4e263e19c31b217",
"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",
- "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/51/5f/ffc90e2af17e3715389bb4ab9a02",
+ "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/5b/c4/2173bc10edea17ed3734f08a8c94",
+ "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/3e/f3/4e9003c88e959d0d75a225c7a87e",
+ "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/9b/b7/c9fd483742201911caeef3d89822",
+ "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",
@@ -939,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",
@@ -1669,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",
@@ -2557,121 +2562,125 @@
"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/80/bf/b80a51b6855fbbc2f19773334c68",
"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/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/_pyio.py": "https://files.ballistica.net/cache/ba1/e6/8e/da9cef09b9375b297ccc45cbedf7",
+ "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/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/4d/98/0c14a8fb30313b4f4d9650772599",
+ "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/c7/5b/fa7fdcd6fe651e33b42e57ef827d",
"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_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/89/ee/3f980b3d7b480c7fe3d34ff876f5",
+ "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/a7/1e/c69f462b1a03515672da486b7a6a",
+ "assets/build/pylib-android/asyncio/exceptions.py": "https://files.ballistica.net/cache/ba1/aa/89/66db5cb3f71048a541224585f7fa",
"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/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/58/44/5520e46a45d5630e95dad27b66d7",
- "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/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/ba/63/856b253fbd572d7b925b552354b8",
- "assets/build/pylib-android/cgitb.py": "https://files.ballistica.net/cache/ba1/45/67/f3f215ae81b670ba05d94706a2ab",
+ "assets/build/pylib-android/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/ae/7f/8b19b4c9d52569b3bdd311e8c799",
+ "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/1b/f3/d9efb6ae310d983d86bb5de9d054",
+ "assets/build/pylib-android/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/d8/21/a266891b38ae68414a3c1b6b3c77",
+ "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/bf/1a/caa31af401c2cc53c5f01b750c80",
+ "assets/build/pylib-android/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/58/72/582cdbbc0857f836dc8c4edbf036",
+ "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/84/8b/185c2457814e6ca8e8688bca9c32",
+ "assets/build/pylib-android/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/4b/1a/1b264ab96fcca89e3eb8fe2614de",
+ "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/ae/3f/acdf9e655546d96a28c484506fe9",
+ "assets/build/pylib-android/binhex.py": "https://files.ballistica.net/cache/ba1/f1/dd/52f057bf1cd0eb01f4f7ae65bab7",
+ "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/88/c3/5db4369b421e58fd76e20d9d6006",
+ "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/e6/ec/de81e7e500b6aae41292320f3f02",
- "assets/build/pylib-android/codecs.py": "https://files.ballistica.net/cache/ba1/75/0f/e06af8024b16ae3d6ad6406a622f",
- "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/code.py": "https://files.ballistica.net/cache/ba1/7a/a4/ee660f11ad995354a3b21efbfb1c",
+ "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/4a/36/f4618c8f8239611208f9fa60d677",
+ "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/63/dc/6feca206d0f5885ac8a0573f6fd0",
+ "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/f8/af/4ea2911df9313c7a7a4f34d6c9eb",
- "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",
"assets/build/pylib-android/ctypes/macholib/dyld.py": "https://files.ballistica.net/cache/ba1/ac/b9/6cd503c12b34f6e72d90ca811910",
"assets/build/pylib-android/ctypes/macholib/dylib.py": "https://files.ballistica.net/cache/ba1/70/15/1df06874f788afb7b6742a5812a7",
"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/util.py": "https://files.ballistica.net/cache/ba1/c5/37/5bc64177f2b03f1b240712b330d5",
"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/4b/89/2740b22a3597dab5c0330ac7c873",
"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/difflib.py": "https://files.ballistica.net/cache/ba1/bb/cf/6db21f4ed1982a8ee1337e12a8c1",
+ "assets/build/pylib-android/dis.py": "https://files.ballistica.net/cache/ba1/7a/6d/8e0820eb6e975bc167a722d30b42",
+ "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/d8/a5/2c5574aedbde0de48d72b06770ef",
+ "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/generator.py": "https://files.ballistica.net/cache/ba1/f6/2c/862c0a2aa12d0e1c0ce1ca305299",
"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/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/message.py": "https://files.ballistica.net/cache/ba1/26/48/c2ba775069f07f9980dd7ba388dc",
"assets/build/pylib-android/email/mime/__init__.py": "https://files.ballistica.net/cache/ba1/42/fb/835abe12a4e1e72a5d1711d12cde",
"assets/build/pylib-android/email/mime/application.py": "https://files.ballistica.net/cache/ba1/47/49/cb957a7a159b5f2259115b7ea27a",
"assets/build/pylib-android/email/mime/audio.py": "https://files.ballistica.net/cache/ba1/67/1e/7ba0091888a55ada476f1300e686",
@@ -2684,9 +2693,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 +2720,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",
@@ -2788,7 +2796,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",
@@ -2798,7 +2806,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 +2817,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/b1/ee/e7435d4112cdaef0192c57f12531",
+ "assets/build/pylib-android/enum.py": "https://files.ballistica.net/cache/ba1/17/fa/2c2e76ce86357e23a5adffd6139f",
"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/53/37/cf10d9be60223979783bd58eed99",
- "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/92/ee/ebce7cc0a8c7a8c49e03603f5f84",
- "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/cb/64/465b1cf482df244287406c2d04d9",
- "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/36/59/f5c4c2dfc97ef6a25e87791eb486",
+ "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/00/c2/b14ed2a7c144df47409a73626f28",
+ "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/8f/95/52b0949ceed253c834f3d683a26c",
- "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/70/fe/b4fb9bfb0218a1baf681c3dd3493",
+ "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/e5/dc/a915c13e827b0f8f5c3d0339a365",
+ "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/59/1f/a5883f250a5a8584a786531159eb",
- "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/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/19/75/05927c752840da64b42ac594e944",
- "assets/build/pylib-android/logging/config.py": "https://files.ballistica.net/cache/ba1/e7/17/c42b6051d993ba8292cf4d1746ac",
- "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/d1/75/8e5a4a91941e362805dc7d43b7a0",
+ "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/be/37/4c3f3e2385e8e6d61d8ef76c5dc4",
"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/ef/5c/151088e70abae8056339e146b943",
- "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/dc/1f/590aefc42b2767560874eebd21ca",
- "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",
- "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/e7/18/74b1980b45e9b0d7aedd6e43f64c",
+ "assets/build/pylib-android/pdb.py": "https://files.ballistica.net/cache/ba1/fc/24/6860b302ac45445af755cf451711",
+ "assets/build/pylib-android/pickle.py": "https://files.ballistica.net/cache/ba1/d4/29/46efdd6acdab82b4ae4810522947",
+ "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/23/0a/090ebfcb1943ca88f9a524f05b6a",
- "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/9a/10/3c865fb4550ae8be364729806f6d",
- "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/d8/c1/eaa9ec920838ec9742eaba62032a",
+ "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/66/da/92943b022e8e4c32ffa45190e6e3",
+ "assets/build/pylib-android/pstats.py": "https://files.ballistica.net/cache/ba1/7a/1e/6651495416e0e70900b036ac1b4f",
+ "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/4f/4f/41b5756b4248c19b3cc6401b616f",
+ "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/31/52/f31201e7ade98dab88d2f36faee8",
+ "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/d4/85/7a836681a4a43361886127d9a5c6",
+ "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/89/dd/17edc05b630cb0bfdea9f0070356",
+ "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/a0/56/4fa028b39079ffceaef1a683f2ff",
+ "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/46/92/4be884871052300c5e7b9a11164b",
- "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/3b/0e/73b187b644f5d861893306db1d11",
+ "assets/build/pylib-android/sysconfig.py": "https://files.ballistica.net/cache/ba1/05/e9/16513caa8a4d9eb20fa67c7a02f1",
"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/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/tarfile.py": "https://files.ballistica.net/cache/ba1/72/ab/e5dfc47c753d7cbb63934aac8fd9",
+ "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/ca/58/e0b1706b032958c6364e7f88adb5",
"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/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/traceback.py": "https://files.ballistica.net/cache/ba1/8b/67/e189e176678255fe36a67f9cfe71",
+ "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/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/89/42/8bf4333174a7fbfe27552743d5af",
"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/types.py": "https://files.ballistica.net/cache/ba1/15/8d/824df2b7a8d28811d23ee5dcbc9f",
+ "assets/build/pylib-android/typing.py": "https://files.ballistica.net/cache/ba1/6e/cc/a870fe92cab98b1d7740da28213c",
"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/ab/9d/cfcebb340b37e3d58ebbfb2fcd23",
+ "assets/build/pylib-android/urllib/request.py": "https://files.ballistica.net/cache/ba1/07/6d/58f034637b48922ec51e7d71b0c1",
"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/8c/4a/f5bf646482975256f504c6543192",
+ "assets/build/pylib-android/uuid.py": "https://files.ballistica.net/cache/ba1/df/2a/cf8755bc0063f6a0d01dee6ac0a3",
+ "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/0b/6d/0f525ade5e00c82e252347350d0d",
+ "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/25/95/2b773a140d7d8cfe4e51d23d9ee2",
"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,142 +2969,147 @@
"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/2c/44/ee7c7ac5086086a64acdbbf2ebd9",
"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/88/73/901cfb9f23cc0bc0a7ba17eebe40",
+ "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/c3/2a/95c24fd76d3dcf796f5aa714cf0b",
"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/3e/7f/2bb850aa1eadc23656adf8fb4fbf",
- "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/dc/7c/1b0ad2f77d1e0f66f87af801c866",
"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_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/59/67/37e8f4938af7ebdea7da3fdef34c",
+ "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/f0/18/e35781df09df31bca6aa14621d71",
+ "assets/build/pylib-apple/asyncio/exceptions.py": "https://files.ballistica.net/cache/ba1/e1/81/9fcc3367d8ebba74819157777a25",
"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/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/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/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/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/39/fd/2f6814cc54d475252da101fbba37",
+ "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/e3/60/b4663ff9e8fa00a097e8b360ff29",
+ "assets/build/pylib-apple/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/e3/c4/d8a03bf572ad495a51250dc6a19b",
+ "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/a1/a8/22d7a8d58241353a5e288b40759f",
+ "assets/build/pylib-apple/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/3a/34/f3cc4d7abb02461d148faf8ef19f",
+ "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/28/6e/301cee24873c77c336504addd197",
+ "assets/build/pylib-apple/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/59/d9/96f8e8e2324dd0400362ff05bd4f",
+ "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/51/50/2e05640cfc2c0a4b61ee3fa028d2",
+ "assets/build/pylib-apple/binhex.py": "https://files.ballistica.net/cache/ba1/51/d9/72daaed73460e29cbf10a63bb7f5",
+ "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/5a/59/5bc5210e1fb224b2942453595609",
+ "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/a2/53/87021ed914efdc55b636a828f8a0",
+ "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/20/45/546d47fe7d97dea6e9913763b620",
- "assets/build/pylib-apple/codecs.py": "https://files.ballistica.net/cache/ba1/19/1d/22a9ce945677366fbd99db8d84e2",
- "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/code.py": "https://files.ballistica.net/cache/ba1/18/fc/d667016222e466707ec5d0991810",
+ "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/95/e2/6ba7d680c393e7ddcf72425a9731",
+ "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/d1/2c/f08c9cc11d79e1cfae3d347396d7",
+ "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/f6/46/146e39a5c6ad47cee4019027d60b",
- "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",
"assets/build/pylib-apple/ctypes/macholib/dyld.py": "https://files.ballistica.net/cache/ba1/cb/c0/d8e7e17b9b3122e1a0fc5ba805cc",
"assets/build/pylib-apple/ctypes/macholib/dylib.py": "https://files.ballistica.net/cache/ba1/bd/b1/b431a9e977498c9c5945a3f63da9",
"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/util.py": "https://files.ballistica.net/cache/ba1/80/95/f30336080c30fcb7d5db549ef68b",
"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/85/e7/aaa5f74230b93068c7bc6df9a645",
+ "assets/build/pylib-apple/datetime.py": "https://files.ballistica.net/cache/ba1/e1/32/e063935d59bbc2d0383228dc93a6",
"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/difflib.py": "https://files.ballistica.net/cache/ba1/63/ca/23738df60b6b3ffe279a617df1bf",
+ "assets/build/pylib-apple/dis.py": "https://files.ballistica.net/cache/ba1/52/8c/c990047191c2cad1f2ce978b146d",
+ "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/fb/2a/efe05a41d7fda3cba1d9a68b31b2",
"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/contentmanager.py": "https://files.ballistica.net/cache/ba1/8b/9e/f72ebcf455884622e5e06828f04a",
+ "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/45/32/b3e671c4ddd645d68e2914de2ec4",
"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/generator.py": "https://files.ballistica.net/cache/ba1/09/86/f9ebd02a5a8a21bd66927b50fffe",
"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/42/92/988e418cd7b901e8fefe1bd98358",
"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/message.py": "https://files.ballistica.net/cache/ba1/53/6f/c22ef21e58ccc9496cdf08d003dc",
"assets/build/pylib-apple/email/mime/__init__.py": "https://files.ballistica.net/cache/ba1/e0/cb/20c79c7faa724bdfeebae99795aa",
"assets/build/pylib-apple/email/mime/application.py": "https://files.ballistica.net/cache/ba1/45/a9/97edc07b0a7c7e3e004422b674c2",
"assets/build/pylib-apple/email/mime/audio.py": "https://files.ballistica.net/cache/ba1/c8/25/9973c555726af5e265c0f459e8b2",
@@ -3110,9 +3122,9 @@
"assets/build/pylib-apple/email/parser.py": "https://files.ballistica.net/cache/ba1/86/8c/8030eb141d7713a36befee9736ef",
"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/email/utils.py": "https://files.ballistica.net/cache/ba1/07/04/1a8a3e3d77eb4b3b31f434514012",
+ "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 +3149,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",
@@ -3214,7 +3225,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",
@@ -3224,7 +3235,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 +3246,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/68/87/a3fbd9a4a710a06e03625e870b37",
"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/36/53/449e18911808fbb40428ad9d314d",
- "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/38/c2/5a14bc48b9488c4d3a1552891035",
- "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/imghdr.py": "https://files.ballistica.net/cache/ba1/c2/84/90721ae9e476f55c9f22e8f18b6b",
+ "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/ce/d8/87e20752d130bbd5dd5e232247c9",
+ "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/58/22/50ad8d061dc8e6c9d59e96bf04fe",
"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/23/3d/9aa84052261a4f0a19d06413ceee",
+ "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/6a/be/1af85e9e3760a22210875ea1e66a",
- "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/e0/5f/793c8e2af7674d58c5da7ed8c6a5",
+ "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/4b/33/905d7110b8f1bdce47d9ca897302",
+ "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/linecache.py": "https://files.ballistica.net/cache/ba1/74/13/4df2fa7a9a0d1879e928afd1b3fa",
+ "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/50/52/03cee68f3d0a5959db0fb4746e6c",
"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/handlers.py": "https://files.ballistica.net/cache/ba1/58/a5/99e0d1cf6e9a35c11d349341f7c6",
+ "assets/build/pylib-apple/logging/__init__.py": "https://files.ballistica.net/cache/ba1/a4/3a/d8719b6afe0790133bb09d168438",
+ "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/6a/26/5e31888d46fc1f0616c2cc5cfc78",
"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/9b/50/39e619d3ea0dbda304627f859782",
+ "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/dc/56/f52a56f95fd67017773f6c0f5ed2",
- "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/34/9d/3198644aa260798e7d3279ada7e6",
- "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/76/0b/2f2ac6ea5e2f56031de310e493da",
+ "assets/build/pylib-apple/pdb.py": "https://files.ballistica.net/cache/ba1/f9/7c/9da21258e7103d43019a8b121957",
+ "assets/build/pylib-apple/pickle.py": "https://files.ballistica.net/cache/ba1/f9/4b/0757ea3efc5c3bd10c325817b5e1",
+ "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/fe/32/9d910017079288d032c48a1c5739",
- "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/db/bc/c8db0b8789383efeb714744754da",
+ "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/6f/e5/b1348f0c118f508d94d24f0a1133",
+ "assets/build/pylib-apple/pstats.py": "https://files.ballistica.net/cache/ba1/94/fb/1e30f0b143965be031f2c3fa4121",
+ "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/3c/04/8cb4b45ddb65e3d8c30521dc3166",
+ "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/0b/3f/191461e95650816203174656fb58",
+ "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/b7/95/4d84e3aaf5c2bd15dfba3fb492e2",
"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/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/smtplib.py": "https://files.ballistica.net/cache/ba1/2c/cc/55e63d5083abe53feaa60b28ad9d",
+ "assets/build/pylib-apple/sndhdr.py": "https://files.ballistica.net/cache/ba1/14/6a/c95a945f5f442e33567069ff95bd",
+ "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/4f/f9/ba5d026d82071429b4ed353b348c",
+ "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/0e/51/da9258c7d2f36f01a9e2af0c037e",
+ "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/1e/1d/a678654eac2ee7df2ebb3f5974fb",
+ "assets/build/pylib-apple/sysconfig.py": "https://files.ballistica.net/cache/ba1/9e/4a/d4f9f5af2ec717c5a1882df63657",
"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/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/2a/52/c64343bf4355d5f2f50a31a55480",
+ "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/80/78/bea27cd8dbca1d14733b18a7f971",
"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/7e/18/925baccd96ba96a79f03d91e762e",
- "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/42/50/c1163bfb4597bfe650d4b9116ca8",
+ "assets/build/pylib-apple/traceback.py": "https://files.ballistica.net/cache/ba1/ca/e6/b80536014c91b58078f251e535fa",
"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/types.py": "https://files.ballistica.net/cache/ba1/21/89/94447b44682aa438ea205a7e4a06",
+ "assets/build/pylib-apple/typing.py": "https://files.ballistica.net/cache/ba1/2a/c9/32965347ba5fa4b4fc0fab4d83c7",
"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/62/f9/b69b5ca52b8b5951b946243b4adb",
+ "assets/build/pylib-apple/urllib/request.py": "https://files.ballistica.net/cache/ba1/14/9d/63afd0699904a811bc6fb993d514",
"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/8c/ad/2d445d2598c0f588db88e9780221",
+ "assets/build/pylib-apple/uuid.py": "https://files.ballistica.net/cache/ba1/02/79/8cb316b2206be3cca67e6680036a",
+ "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/29/57/574eac7a24d3fca5921287a4e42e",
+ "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/a1/e0/c43c65b7330f037c51ee10009ba7",
"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,760 +3398,574 @@
"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/24/b4/16f98ca0ce1d018ef86c370bba72",
"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/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/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/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/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/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/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",
- "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/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",
- "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/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",
- "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/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",
- "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/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",
- "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/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",
- "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/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/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",
- "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/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",
- "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/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",
- "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-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",
- "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/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",
- "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/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",
- "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/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",
- "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/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/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/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"
+ "assets/build/pylib-apple/zipfile.py": "https://files.ballistica.net/cache/ba1/f2/7b/5614676b914cfbed897919046f1c",
+ "assets/build/pylib-apple/zipimport.py": "https://files.ballistica.net/cache/ba1/1f/fa/e11a7b5e9b1191a74bb80f48dc9f",
+ "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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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",
+ "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/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/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",
+ "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/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",
+ "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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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",
+ "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/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/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/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/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/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/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",
+ "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/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_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/34/03/fa17556f6237dfdcebf9afd8f279",
+ "build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9e/c5/5c2d87c017752097edee41e279a4",
+ "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c5/c2/797e0930db43aabbd2aaf7ac8496",
+ "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/19/a0fbbd13540d5931c5efbf62dc38",
+ "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2b/46/66d45845b5abe8098531a573aff8",
+ "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/35/a6/914b15bc43529559b3ccb17578b4",
+ "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1b/75/02980e88b129f0a9b06ff7eac860",
+ "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/62/4ff2583b91609158a13238582082",
+ "build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2b/1d/c824a5a7f3051cba893ad484bc3f",
+ "build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ba/b7/c8314f563cdccf09453086ebfa71",
+ "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/b1/404f7718e7db5529401272c677a0",
+ "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/84/fd/756410f7c791a3b2799c33479d74",
+ "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/13/41/555492d43925e24d4251a9127d01",
+ "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e4/cb/544983180fc03f8069718be2493f",
+ "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/6f/744e43e527d878bb351a980b9bd6",
+ "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/37/2c/25dd66b5af2ec2990f5b45a06932",
+ "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/47/20/2759204b27a320a456dc07299b91",
+ "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bd/f2/4c0705b107aaf57c88264e42ba51",
+ "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cc/7a/664f3cf3a5b6d4be571e1af3415b",
+ "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/08/fe/ed6c794bd1c20ab1bf09ba5a3982",
+ "build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b7/6e/9e62c5daa7ebd640f73aa4105dc9",
+ "build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5e/0f/c157ced802e04c0d74ce8cf4ce84",
+ "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/23/27/1610c8533aed71a835e2a95b64c7",
+ "build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/83/94/bda40769e333dbe9b0bcb08061ff",
+ "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3f/e5/ac0ca3e1e34130b54afafdbf4f9a",
+ "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0f/f7/f7ff933c91852602aadc4af02f5b",
+ "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/78/5b/de61880a1c37d77fef5ea71c4f18",
+ "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/71/18/348b78b44229e2245eb5cf18a9ab",
+ "build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/94/d5/489bbcaa836118c0a8189115f97b",
+ "build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7a/20/7ced97ccc4096756931dfd1f1f91",
+ "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a4/59/bd805cfde4724c2605035683f207",
+ "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d9/bb/f25b3982b1471c53ffdc0d494066",
+ "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/08/57/209d879949c2aba25355df7016e9",
+ "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/20/6c/1bcab90ac28d8b801ff524003d41",
+ "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9e/86/2eba2ff1adf657e2e2f436f9fa99",
+ "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6b/f6/4bab12aaba4e95e6a5b442d2c0f7"
}
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..8cbc3eff
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,32 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: Bug
+labels: bug
+assignees: ''
+
+---
+
+## Description
+Describe the bug. Do not forget to fill the title.
+
+## Steps to reproduce
+1. Launch BombSquad
+2. Go to '...'
+3. Press '...'
+4. Bug!
+
+## Expected behavior
+Describe what you think should happen.
+
+## Machine
+**Platform**: Windows 10 / Ubuntu 20.04 LTS / AOSP 8.1 / etc.
+**BombSquad version**: [1.5.27](https://github.com/efroemling/ballistica/releases/tag/v1.5.27)
+**Commit**: [2642488](https://github.com/efroemling/ballistica/commit/2642488a51b250752169738f5aeeccaafa2bc8de)
+Select what do you want to use: release version or commit. Please use a hyperlink.
+
+## Screenshots
+Put some screenshots here if needed.
+
+## Extra
+Put some extra information here. For example, describe your assumptions about the cause of the bug.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..e40e948b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for BombSquad
+title: Feature Request
+labels: enhancement
+assignees: ''
+
+---
+
+## Description
+Describe feature that you want.
+
+## Solution
+A clear and concise description of what you want to happen.
+
+## Alternatives
+A clear and concise description of any alternative solutions or features you've considered.
+
+## Additional context
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/want-to-discuss-something-or-ask-a-question-.md b/.github/ISSUE_TEMPLATE/want-to-discuss-something-or-ask-a-question-.md
new file mode 100644
index 00000000..bdcda739
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/want-to-discuss-something-or-ask-a-question-.md
@@ -0,0 +1,10 @@
+---
+name: Want to discuss something or ask a question?
+about: GitHub Discussions are waiting for you
+title: Discussion
+labels: ''
+assignees: ''
+
+---
+
+We're using [GitHub Discussions](https://github.com/efroemling/ballistica/discussions)! Asking and answering questions is much more convenient there than in Issues.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5a0a64d4..6eee5ac5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,36 +11,49 @@ 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.
- ci_unix:
- runs-on: ubuntu-18.04
+ # 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.
+ check_linux:
+ 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/snippets install_pip_reqs
+ run: tools/pcommand install_pip_reqs
- name: Run checks and tests
run: make -j2 check test
+ # Compile just a server binary but don't run asset builds/etc.
+ # (to spare my asset file server)
+ compile_linux:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v1
+ - name: Set up Python
+ uses: actions/setup-python@v1
+ with:
+ python-version: 3.8
+ - name: Compile binary
+ run: make _cmake-simple-ci-server-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.
- ci_windows:
+ # (filesystem, etc) can vary significantly between windows and linux/apple.
+ check_windows:
runs-on: windows-latest
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: |
python -m pip install --upgrade pip
- pip install pytest
+ pip install pytest typing_extensions
- name: Run tests
- run: python tools/snippets pytest -v tests
+ run: python tools/pcommand pytest -v tests
diff --git a/.gitignore b/.gitignore
index a7a23f24..ae948644 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,7 +23,6 @@ local.properties
.flycheck-dir-locals.el
.pylintrc
.projectile
-.editorconfig
.clang-format
.style.yapf
.irony
@@ -74,7 +73,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..a385081f 100644
--- a/.idea/ballisticacore.iml
+++ b/.idea/ballisticacore.iml
@@ -62,8 +62,9 @@
+
-
+
\ No newline at end of file
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index c56af62a..550aa380 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -15,7 +15,9 @@
aarch
abcdefghijklmnopqrstuvwxyz
abeb
+ abishort
abot
+ abouttab
abtn
accesstime
accountname
@@ -29,17 +31,23 @@
achs
acinstance
ack
+ ack'ed
acked
acks
acnt
actionhero
activityname
+ activityplayer
+ activityteam
activitytypes
activityutils
actorclass
adbcfaca
adbpath
+ addcall
+ addchars
addgame
+ addlevel
addr
addrstr
adisp
@@ -51,6 +59,7 @@
allsettings
allteams
aman
+ amazonaws
aname
anamorphosis
andr
@@ -60,7 +69,10 @@
animcurve
anota
anroid
+ ansiwrap
antigravity
+ anyofallof
+ aosp
apichanges
apis
apks
@@ -76,6 +88,9 @@
appkit
applescript
appletv
+ appmode
+ appname
+ appnameupper
appstate
appstore
apputils
@@ -84,12 +99,15 @@
archs
argh
argparse
+ argsjoined
+ argtypes
argval
armeabi
arraymodule
asdict
aspx
assertnode
+ asserttype
assetbundle
assetcache
assetdata
@@ -105,6 +123,7 @@
assetpath
assettype
assettypestr
+ assigninput
astc
astcenc
astroid
@@ -129,6 +148,8 @@
autoretain
autoselect
autotools
+ availmins
+ availplug
aval
axismotion
bacfg
@@ -140,6 +161,7 @@
badguy
bafoundation
ballistica
+ ballistica's
ballisticacore
ballisticacorecb
bamaster
@@ -148,19 +170,25 @@
baseh
basemult
basepos
+ baservnode
basespaz
basetime
baseurl
+ baseval
basew
+ basn
bastd
batools
+ bbbb
bblk
bblu
bbot
bbtn
bcppcompiler
bcyn
+ bdea
bdfl
+ bdir
belarussian
benboncan
bfiledir
@@ -180,17 +208,21 @@
blas
blastos
bldtp
+ blesspath
blocksize
bluetooth
bmag
bname
bndl
boffs
+ bombfactory
bombsquad
bombsquadcb
bombsquadgame
bools
bootlocale
+ borhani
+ bot's
botdist
botlist
botpos
@@ -211,14 +243,23 @@
bsplaylist
bsremote
bsstd
+ bstat
bstournament
bsuffix
bsui
btnh
+ btnlabel
btnv
btnx
+ btype
+ bucketnum
+ buildblessing
+ buildblessingcheck
builddir
buildfile
+ buildfilename
+ buildnum
+ buildserver
buildtype
bullseye
bumpmap
@@ -244,6 +285,7 @@
cameraflash
camerashake
campaignname
+ cancelbtn
capb
capturetheflag
carentity
@@ -251,6 +293,7 @@
cbits
cbot
cbtn
+ cbtnoffs
ccfgs
ccode
ccompiler
@@ -260,9 +303,11 @@
centeuro
centiseconds
cfconfig
+ cfenv
cfgdir
cfgkey
cfgkeys
+ cfgpath
cfgs
cfgui
cflags
@@ -278,8 +323,11 @@
charname
charstr
chatmessage
+ chdir
+ cheadersline
checkarg
checkboxwidget
+ checkchisel
checkenv
checkfast
checkfull
@@ -287,11 +335,13 @@
checkpaths
checkroundover
checksums
+ checktype
childnode
chinesetraditional
chipfork
chosenone
chromebooks
+ chunksize
cjkcodecs
classmethod
classmethods
@@ -299,11 +349,17 @@
classnames
cleancheck
cleanlist
+ cleanupcheck
+ cleanupchecks
clientid
clientlist
clionbin
clioncode
clionroot
+ clipcount
+ cloudbuild
+ cloudshell
+ cloudshellbuild
cloudtool
cloudtoolcmd
clrblu
@@ -312,14 +368,19 @@
clrhdr
clrnames
clrred
+ cmakelists
+ cmakeserver
cmathmodule
cmds
cmembers
cmodel
+ cmpf
cnode
codecsmodule
codefilenames
+ codefiles
codehash
+ codelines
codeop
collapsable
collidemodel
@@ -337,12 +398,14 @@
compounddict
compoundlist
conditionalize
+ configdict
configerror
confighash
configkey
configparser
configpath
connectattr
+ conout
containerwidget
contentmanager
contextlib
@@ -367,35 +430,47 @@
cornerpin
coroutines
countdownsounds
+ cpbd
+ cpnf
cpplint
cpplintcode
cpplintcodefull
cpplintfull
+ cpplintmodule
cpuinfo
cpus
cpython
crashlytics
creationflags
creditslist
+ cresult
cryptmodule
+ cspbd
+ cspnf
+ cspre
cssclass
+ csspbt
cstr
csum
ctest
ctex
ctuple
ctype
+ cupcmd
curdir
curhash
curhashes
curstate
curtime
curtimestr
+ customdata
customizebrowser
cutscenes
cval
cwdg
+ cxxabi
cyaml
+ cycledelay
cygwinccompiler
darwiin
darwiinremote
@@ -409,12 +484,16 @@
daynum
dayoffset
dbapi
+ dbase
+ dbgsfx
+ dbgstr
dbpath
dcls
dcmake
deathmatch
deek
defs
+ defsline
deivit
depcls
depdata
@@ -436,6 +515,7 @@
diemessages
difflib
dilateerode
+ dincrease
dingsound
dingsoundhigh
dirmanifest
@@ -452,6 +532,7 @@
distroot
distros
dline
+ dlldir
dlls
dmitry
dmodule
@@ -478,6 +559,7 @@
downmix
dpad
dpath
+ dprofilename
drawscore
drawscreen
dripity
@@ -488,6 +570,7 @@
dstattr
dstbase
dstdata
+ dstdirname
dstfile
dstfin
dstjson
@@ -519,39 +602,54 @@
editcontroller
editgame
editorconfig
+ efgrd
efile
efro
efrocache
efrocachemap
efroemling
+ efrogradle
+ efrohack
+ efrohome
efrosync
efrotool
efrotools
eftools
efxjtp
eids
+ elapsedf
elementtree
elim
emitfx
emoji
+ emojis
enablexinput
ename
encerr
endcall
endcommand
+ endef
endindex
endmessage
endparen
endtime
+ englishkeyboard
ensurepip
entitylist
entrynew
+ entrystorename
entrytype
entrytypeselect
enumtype
enumval
+ enumvalue
+ enval
+ envcfg
envhash
+ envname
+ envs
envval
+ envvar
epath
epicfail
ericf
@@ -566,10 +664,12 @@
etsel
etxt
etype
+ eval'ed
evalpydata
evel
eventid
ewww
+ ewwww
excludepowerups
excludetypes
excstr
@@ -577,6 +677,8 @@
execlocals
executils
exhash
+ existable
+ existables
expatbuilder
expatreader
explodable
@@ -588,9 +690,15 @@
extrahash
extrascale
exts
+ f'baseval
+ f'chmod
+ f'final
+ f'fixme
factoryclass
+ fakemodule
fallbacks
farthestpt
+ fback
fbase
fclose
fcmd
@@ -601,13 +709,18 @@
fdata
fdesc
fdict
+ fdout
fecfc
feedparser
+ ffaeff
ffap
+ fflush
fhash
fhashes
fhdr
fieldattr
+ fieldname
+ fieldpath
fieldsdict
fieldtype
fieldtypes
@@ -626,6 +739,8 @@
filterlines
filterpath
filterpaths
+ filterstr
+ filterval
finalhash
finalmaterials
finfo
@@ -633,6 +748,7 @@
firestore
firetv
firstline
+ firstpartykey
flac
flagmat
flagmaterial
@@ -675,15 +791,19 @@
fprint
fproject
fpsc
+ frameinfo
+ frameline
framerate
freefly
freeforallendscreen
freeforallsession
freeforallvictory
+ freemins
freepik
freesound
froemling
frombuffer
+ fromini
fsdf
fsettings
fsplit
@@ -723,12 +843,16 @@
gameinstance
gamemap
gamepad
+ gamepad's
gamepadadvanced
gamepads
gamepadselect
gameplay
+ gameplayer
gameport
gameresults
+ gamesettings
+ gameteam
gametype
gametypes
gameutils
@@ -740,28 +864,42 @@
genmapjson
genstartercache
genutils
+ getaccountid
getactivity
+ getcampaign
getclass
getcollide
getcollidemodel
+ getcollision
getconf
getconfig
getcurrency
getcwd
getdata
+ gethostbyname
+ getinputdevice
+ getkillerplayer
+ getlevel
getlevelname
+ getlevels
+ getlocalconfig
+ getlog
getmaps
getmodel
+ getname
getnodes
getnodetype
getopt
getplayer
getpt
getremote
+ getres
getscanresults
+ getscoreconfig
getsession
getsockname
getsound
+ getspaz
getstarttime
gettext
gettexture
@@ -782,6 +920,7 @@
gnode
goles
goodlist
+ googleplaytab
googlevr
goosey
gotresponse
@@ -816,7 +955,10 @@
hasstarted
hatmotion
hattach
+ hcalc
+ hcfg
hdpi
+ headercheckline
headerregistry
heapqmodule
hehe
@@ -832,15 +974,25 @@
hmac
hmmm
hmmmm
+ hmph
hoffs
+ holdingflag
+ holdingteam
+ holdingteams
holdposition
homebook
homebrew
hometest
+ hostconfig
+ hostingconfig
+ hostingstate
+ hostuser
+ hout
howtoplay
hpos
hscrollwidget
hspacing
+ httprequest
hurtiness
hval
iasset
@@ -848,10 +1000,13 @@
icns
iconpicker
iconscale
+ iconsstorename
ident
idevices
ifeq
ifneq
+ iiarcade
+ iircade
ilang
ilck
ilogput
@@ -861,6 +1016,7 @@
imagestacklayer
imagewidget
imaplib
+ imgdelay
imgh
imghdr
imgw
@@ -884,6 +1040,7 @@
infotextcolor
inidividual
initializers
+ initialplayerinfos
initing
inits
inmobi
@@ -893,14 +1050,21 @@
inputfiles
inputhash
inputnode
+ inputter
+ inputtype
inpututils
inspectdir
insta
installdir
instancer
+ interfacetype
+ internalsrc
interstitials
intex
+ intp
introspectable
+ intstr
+ iobj
ipaddress
ipos
iprof
@@ -909,6 +1073,7 @@
iserverget
iserverput
ispunch
+ ispunched
isubval
isysroot
itms
@@ -927,14 +1092,19 @@
joedeshon
johab
joinable
+ joinmsg
jovica
jsonstr
jsonstrbase
jsontools
jsonutils
+ kbclass
kbytecount
+ keepalive
+ keepalives
keepaway
keeprefs
+ keyfilt
keylayout
keypresses
keystr
@@ -942,6 +1112,7 @@
keywd
keywds
khronos
+ kickable
kickin
kickstart
killcount
@@ -959,6 +1130,7 @@
langs
langtarget
langval
+ larmbeast
lasthash
lastline
lastplayer
@@ -969,6 +1141,7 @@
lazybuilddir
lbits
lbld
+ lbval
lcfg
lcolor
lcrypto
@@ -977,17 +1150,26 @@
leaderboards
leady
lenglishvalues
+ lenval
levelgametype
levelmodule
levelname
lfull
+ lfval
+ libballisticacore
libcrypto
+ libdir
libegl
+ libext
+ libffi
+ libgen
libinst
liblzma
libmain
+ libogg
libopena
libopenal
+ libpath
libpython
libsd
libsdl
@@ -995,15 +1177,20 @@
libssl
libvorbi
libvorbis
+ libvorbisfile
libxm
libxmu
libxz
+ linbeast
lindex
lindexorig
+ linearstep
+ linebits
lineheight
lineno
linenum
linenumber
+ linenums
linetype
linetypes
linflav
@@ -1016,6 +1203,7 @@
lintscriptsfast
listobj
listvalidconfigs
+ lival
llzma
lmerged
lmod
@@ -1029,11 +1217,16 @@
lnums
loadpackage
localconfig
+ localdir
+ localuser
locationgroup
locationgroups
locationlist
locationsingles
locationval
+ lockpath
+ lockstr
+ locktype
locs
logcat
logintoken
@@ -1042,6 +1235,7 @@
loofa
loosey
losecount
+ lpdword
lpos
lprop
lsbo
@@ -1051,8 +1245,11 @@
lssl
lstart
lstr
+ lstr's
lstrs
+ lsval
ltex
+ ltypes
lzma
lzmamodule
macappstore
@@ -1068,6 +1265,7 @@
malformatted
mallimportedby
mandir
+ manualtab
mapdata
mapdef
mapdefs
@@ -1076,11 +1274,15 @@
mapselect
maptype
markupbase
+ masktex
+ masktexstorename
+ masterhash
mathmodule
mathnode
mathutils
maxdepth
maxlinks
+ maxtries
maxval
maxw
maxwidth
@@ -1097,9 +1299,12 @@
meteorshower
mfpath
mhash
+ mhbegin
+ mhend
mhsh
microprotocols
mikirog
+ millisecs
mimetypes
mimportedby
mindepth
@@ -1123,19 +1328,24 @@
modder
modders
modename
+ modestr
+ modeval
modpack
modtimes
moduledir
modulefinder
modulename
+ modulepath
modutils
moola
mopaque
+ moreso
mpath
mrmaxmeier
msbuild
mshell
msvccompiler
+ msvcp
mtarget
mtime
mtrans
@@ -1169,6 +1379,7 @@
myhome
myinput
mylist
+ mymodule
mynode
myobj
myprojname
@@ -1179,16 +1390,23 @@
mypytype
mysound
mytextnode
+ mythingie
myweakcall
mywidget
namedarg
nametext
+ nameval
nboxes
ncpu
ndbm
ndkpath
+ nearbytab
neededsettings
ness
+ netcode
+ netlink
+ netplay
+ nettest
nettesting
netutils
nevermind
@@ -1207,31 +1425,44 @@
nline
nlines
nntplib
+ noassets
nodeactor
nodepos
nodpi
nofiles
noinspect
+ nondeterministic
noninfringement
+ noninteractive
+ noninteractively
nonmultipart
noone
norun
nospeak
nosub
nosyncdir
+ nosyncdirlist
nosyncdirs
+ nosyncfile
+ nosyncfilelist
+ nosyncfiles
+ nosynctool
nosynctools
notdir
+ nowtickets
npos
nprocessors
ntpath
ntriple
nturl
numedit
+ numsound
numstr
+ nval
nvcompress
nvidia
nyko
+ obj's
objname
objs
objt
@@ -1239,13 +1470,17 @@
obval
occurrances
oculus
+ oenval
offsanchor
+ offsx
+ offsy
ofval
oggenc
oghash
oghashes
ogval
oival
+ okbtn
oldlady
onln
onscreencountdown
@@ -1257,6 +1492,8 @@
openssh
operasinger
oppnode
+ opposingbody
+ opposingnode
opstr
optparse
orchestrahitsound
@@ -1268,15 +1505,20 @@
osval
otherplayer
otherspawn
+ ourhash
ourself
outdata
outdelay
outext
outfilename
outfilepath
+ outhashpath
outname
outpath
+ outputter
+ outvalue
ouya
+ overloadsigs
packagedir
packagedirs
packagename
@@ -1287,7 +1529,9 @@
palmos
pandoc
pandroid
+ parallelized
parsermodule
+ parsetok
partyqueue
partyval
passnode
@@ -1297,6 +1541,7 @@
pathlib
pathnames
pathstonames
+ pathtmp
patsubst
pausable
pbrowser
@@ -1304,11 +1549,13 @@
pbxproj
pcall
pchild
+ pcommand
pcstr
pedit
peditui
pentry
perma
+ perrdetail
phasers
phello
photoshop
@@ -1319,12 +1566,17 @@
pipname
pkey
pkgutil
+ playercast
+ playerdata
+ playerinfos
playerlostspaz
playernode
playerpt
playerpts
playerrec
playerspaz
+ playerteamdata
+ playertype
playerval
playlistui
playmode
@@ -1338,6 +1590,11 @@
plistname
plpt
plst
+ plugkey
+ plugkeys
+ pluglist
+ plugstate
+ plugstates
plusbutton
plvel
pmats
@@ -1357,6 +1614,9 @@
positionadjusted
posixpath
posixsubprocess
+ postinit
+ postinited
+ postrun
poststr
powerdown
powersgiven
@@ -1367,10 +1627,14 @@
poweruptype
powervr
ppos
+ pproxy
+ pptabcom
pragmas
prch
prec
+ precommand
preexec
+ prefablib
preflightfast
preflightfull
preflighting
@@ -1383,13 +1647,18 @@
premultiplied
premultiply
preprocessing
+ prereq
prereqs
+ prerun
+ prevstate
priceraw
printcolors
+ printf
printnodes
printobjects
printpaths
priv
+ privatetab
proactor
proc
procs
@@ -1399,6 +1668,7 @@
profilenames
proj
projconfig
+ projdir
projectpath
projectroot
projroot
@@ -1416,6 +1686,7 @@
pthreads
ptrans
ptype
+ publictab
pubsync
pucknode
pulllist
@@ -1431,6 +1702,7 @@
pushdocs
pushish
pushlist
+ pushsymbols
putasset
putassetmanifest
putassetpack
@@ -1447,6 +1719,7 @@
pybee
pybuild
pycache
+ pycharm's
pycharmbin
pycharmfull
pycharmroot
@@ -1478,15 +1751,21 @@
pypaths
pysources
pytest
+ pythondirs
pythondontwritebytecode
+ pythonhashseed
pythonpath
+ pythonpaths
pythonw
pytree
pytz
+ pyver
qrcode
qrencode
qual
+ qualname
quoprimime
+ rando
randommodule
randval
rankbutton
@@ -1503,6 +1782,7 @@
realsies
recache
redist
+ redistributables
relpath
remainingchecks
remoteapp
@@ -1512,10 +1792,16 @@
reqtype
reqtypes
resample
+ resetbtn
+ resetinput
resourcetypeinfo
respawn
+ respawnable
+ respawned
respawnicon
responsetype
+ resultstr
+ retrysecs
returncode
returnfuncptrs
returnspc
@@ -1528,6 +1814,7 @@
rfudge
rgba
rlcompleter
+ rlock
rmats
rmine
robotparser
@@ -1542,18 +1829,23 @@
rsdr
rsms
rstr
+ rtnetlink
rtxt
runmypy
runonly
runpy
+ runpylint
runswindows
rval
safecolor
safesetattr
+ safesetcolor
saitek
samsung
sandboxing
sandyrb
+ savebtn
+ savebutton
saxutils
sbblk
sbblu
@@ -1573,9 +1865,11 @@
sched
sclx
scly
+ scoreconfig
scorescreen
scoreteam
scoretxt
+ scoretype
scoreval
scorever
scorings
@@ -1587,32 +1881,55 @@
scrlw
scrollw
scrollwidget
+ scsb
scyn
sdata
+ sdkcheck
sdkutils
sdtk
+ selchild
selectmodule
+ selindex
+ selwidget
+ selwidgets
senze
+ seqtype
+ seqtypestr
serverbuild
servercallthread
servercallthreadtype
servercfg
servercmd
serverdialog
+ serverdst
serverget
servermanager
servermode
+ servernodes
serverput
serverutils
sessionclass
sessiondata
sessionglobals
+ sessionglobalsnode
sessionname
+ sessionplayer
+ sessionplayers
+ sessionteam
+ sessionteam's
+ sessionteams
sessiontype
+ sessiontypestr
+ setactivity
setalpha
setbuild
+ setconfig
+ setdata
setlanguage
setmusic
+ setname
+ setnode
+ setsticky
settingname
setversion
sgrn
@@ -1620,8 +1937,11 @@
sharedctypes
sharedobj
sharedobjs
+ shellapi
shiftdelay
shiftposition
+ shiplog
+ shobs
shortname
shouldn
showpoints
@@ -1630,27 +1950,35 @@
shroom
shutil
simplesubclasses
+ simpletype
sincelaunch
singledispatch
+ singledispatchmethod
sirplus
sitebuiltins
skey
sline
slval
smag
+ smallscale
smlh
+ smoothstep
+ smoothy
smtpd
smtplib
smush
snakeshadow
sname
snode
+ sockaddr
socketmodule
socketserver
somevar
soundtrackname
sourceimages
sourcelines
+ sourcenode
+ spacecount
spacelen
spacingstr
spammers
@@ -1658,13 +1986,16 @@
sparx
spawner
spawners
+ spawninfo
spawnpoints
spawnpt
+ spawnrate
spawntype
spaz
spazappearance
spazbot
spazfactory
+ spaztype
spazzes
spcall
spcstr
@@ -1673,6 +2004,8 @@
spinoff
spinoffdata
spinoffs
+ spinup
+ splayer
splitlen
splitnumstr
squadcore
@@ -1683,6 +2016,7 @@
srcnode
srcpath
srcpathfull
+ srcplayer
srcpy
srcpydata
srcstr
@@ -1690,6 +2024,7 @@
sred
sshd
sslproto
+ ssval
stackstr
standin
starscale
@@ -1713,15 +2048,21 @@
steelseries
stickman
storable
+ storagename
+ storecmd
storedhash
storeitemui
+ storename
strftime
stringprep
stringptr
+ strippable
strobing
strptime
+ strs
strt
strval
+ subargs
subclassof
subcontainer
subcontainerheight
@@ -1730,14 +2071,21 @@
subdep
subdeps
subdirs
+ subfieldpath
subfolders
+ subname
subpath
+ subpaths
subplatform
subplatforms
+ subprocess's
subprocesses
subrepos
subsel
+ subtypestr
subval
+ subvalue
+ subvaluetype
successfull
suiciding
sunau
@@ -1755,7 +2103,9 @@
syncable
syncall
syncalllist
+ synccfg
synccheck
+ syncconfig
syncforce
syncfull
syncitem
@@ -1764,7 +2114,12 @@
sysconfigdata
sysctl
syslogmodule
+ tabdefs
+ tabtype
+ tabtypes
tabval
+ tagargs
+ tagversion
taobao
taobaomascot
targ
@@ -1783,11 +2138,13 @@
tdelay
tdval
teambasesession
+ teamdata
teamgame
teamnamescolors
teamsize
teamsscorescreen
teamssession
+ teamtype
teeeeeeeesssssttttdddddddd
teehee
teleporting
@@ -1795,6 +2152,7 @@
tempfile
tempfilepath
templatecb
+ tenum
termcolors
termios
testbuffer
@@ -1803,6 +2161,7 @@
testcapi
testcapimodule
testclass
+ testconsole
testd
testdl
testfoo
@@ -1813,6 +2172,7 @@
testm
testmagicmethods
testmock
+ testmultiphase
testobj
testpatch
testpath
@@ -1835,14 +2195,18 @@
thanvannispen
thelaststand
themself
+ thingie
+ this'll
threadtype
throwiness
+ ticon
timedisplay
timeformat
timemax
timemin
timeremaining
timestep
+ timesteps
timestring
timestrval
timetype
@@ -1863,13 +2227,18 @@
topkillcount
topkilledcount
toplevel
+ toplevelfiles
totaldudes
totalpts
+ totaltime
+ totalwaves
+ totype
touchpad
tournamententry
tournamentscores
tplayer
tpos
+ tproxy
tracebacks
tracemalloc
tradeoff
@@ -1879,8 +2248,11 @@
tref
tret
trophystr
+ trsock
+ trynum
tscale
tscl
+ tself
tspc
tstr
turtledemo
@@ -1898,6 +2270,7 @@
typeargs
typecheck
typechecker
+ typechecker's
typedval
typeshed
typestr
@@ -1905,6 +2278,7 @@
tzinfos
uadfc
uber
+ ucrtbased
ugrade
uibounds
uicleanup
@@ -1918,12 +2292,14 @@
uname
unbounds
uncollectible
+ underruns
unforunate
unimported
uninferrable
uninited
uniquify
unixccompiler
+ unknownlintline
unlinkable
unlinking
unlinks
@@ -1938,6 +2314,7 @@
unranked
unstaged
unstripped
+ unstrl
unsubscriptable
untracked
upcase
@@ -1945,8 +2322,10 @@
updatethencheck
updatethencheckfast
updatethencheckfull
+ upkeeptimer
uploadargs
uploadcmd
+ uppercased
uptime
ureq
useragent
@@ -1959,6 +2338,7 @@
valnew
vals
valuedispatch
+ valuedispatchmethod
valueerror
valuetext
valuetype
@@ -1966,8 +2346,11 @@
varname
varsize
vartype
+ vcruntime
vcxproj
venv
+ verfilename
+ verlines
versioning
versionpredicate
vert
@@ -1995,8 +2378,11 @@
vtype
vval
waaah
+ waittime
wanttype
+ warntype
wasdead
+ wavenum
weakref
weakrefs
weakrefset
@@ -2005,18 +2391,27 @@
webpages
whatevs
wheee
+ whos
widgetdeathtime
wiimote
wiimotes
willeval
+ winbeast
wincfg
wincount
+ winempty
+ winnergroup
+ winnergroups
+ winplat
winplt
winprj
+ winprune
winref
winscore
+ winserver
winsound
winstate
+ wintype
wmsbe
woooo
workdir
@@ -2025,6 +2420,8 @@
wref
writeclasses
writefuncs
+ wslpath
+ wsroot
wtcolor
wtflib
wttxt
@@ -2065,6 +2462,7 @@
yapf
yapfconfig
yinyang
+ yoffs
ypos
yres
yscl
diff --git a/.idea/dictionaries/roman.xml b/.idea/dictionaries/roman.xml
new file mode 100644
index 00000000..240cd39e
--- /dev/null
+++ b/.idea/dictionaries/roman.xml
@@ -0,0 +1,8 @@
+
+
+
+ maxlen
+ pagename
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Default.xml b/.idea/inspectionProfiles/Default.xml
index 869f7d0f..5884173f 100644
--- a/.idea/inspectionProfiles/Default.xml
+++ b/.idea/inspectionProfiles/Default.xml
@@ -2,6 +2,8 @@
+
+
@@ -42,6 +44,7 @@
+
@@ -50,8 +53,9 @@
+
-
+
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 b0c46787..47695f2b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,12 +1,197 @@
+### 1.6.0 (20333)
+- Revamped netcode significantly. We still don't have client-prediction, but things should (hopefully) feel much lower latency now.
+- Added network debug graphs accessible by hitting F8.
+- Added private parties functionality (cloud hosted parties with associated codes making it easier to play with friends)
+- The meta subsystem now enables new plugins by default in headless builds.
+- Added option to save party in Manual tab
+- Slight tidying on the tourney entry popup
+- Env var to override UI scale is now `BA_UI_SCALE` instead of `BA_FORCE_UI_SCALE`.
+- Fixed an issue where ba.storagename() could prevent objects on the stack from getting released cleanly
+- Improvements to documentation generation such as link to some external base types.
+- Added `ba.clipboard_*` functions for copying and pasting text on supported platforms.
+- Implemented clipboard functionality on SDL based builds (such as prefab).
+- Fixed an issue where click locations on scaled text fields could be incorrectly calculated.
+- Server-wrapper improvements allowing config path and ba_root path to be passed explicitly.
+- Binary -cfgdir option now properly allows any path, not just './ba_root'.
+- Additional server-wrapper options such as disabling auto-restart and automatic restarts on config file changes.
+- Running a `_ba.connect_to_party` command via the -exec arg should now do the right thing.
+- Fixed possible crash due to buffer under/overruns in `Utils::precalc_rands_*`.
+- Fixed a potential crash-on-exit due to statically allocated colliders/caches in `ode_collision_trimesh.cpp` getting torn down while in use
+
+### 1.5.29 (20246)
+- Exposed ba method/class initing in public C++ layer.
+- The 'restart' and 'shutdown' commands in the server script now default to immediate=True
+- Wired up `clean_exit_minutes`, `unclean_exit_minutes`, and `idle_exit_minutes` options in the server config
+- Removed remains of the google-real-time-multiplayer stuff from the android/java layer.
+
+### 1.5.28 (20239)
+- Simplified `ba.enum_by_value()`
+- Updated Google Play version to hopefully show friend high scores again on score screens (at least for levels that have an associated Google Play leaderboard).
+- Public-party-list now properly shows an error instead of 'loading...' when not signed in.
+- Heavily reworked public party list display code to be more efficient and avoid hitches even with large numbers of servers.
+
+### 1.5.27 (20238)
+- Language functionality has been consolidated into a LanguageSubsystem object at ba.app.lang
+- `ba.get_valid_languages()` is now an attr: `ba.app.lang.available_languages`
+- Achievement functionality has been consolidated into an AchievementSubsystem object at ba.app.ach
+- Plugin functionality has been consolidated into a PluginSubsystem obj at ba.app.plugins
+- Ditto with AccountSubsystem and ba.app.accounts
+- Ditto with MetadataSubsystem and ba.app.meta
+- Ditto with AdsSubsystem and ba.app.ads
+- Revamped tab-button functionality into a cleaner type-safe class (bastd.ui.tabs.TabRow)
+- Split Gather-Window tabs out into individual classes for future improvements (bastd.ui.gather.\*)
+- Added the ability to disable ticket-purchasing UIs for builds (`ba.app.allow_ticket_purchases`)
+- Reworked the public party gather section to perform better; it should no longer have to rebuild the list from scratch each time the UI is visited.
+- Added a filter option to the public party list (sorry it has taken so long).
+
+### 1.5.26 (20217)
+- Simplified licensing header on python scripts.
+- General project refactoring in order to open source most of the C++ layer.
+
+### 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
+- 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..
+- 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`.
+- 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.
+- 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).
+
+### 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.
+
+### 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.
+- 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.
+- 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.
+- 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.
+
+### 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.
+
+### 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.
+
+### 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.
+
+### 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
+- 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.
+- 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.
+
+### 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.
+- Fixes an issue where Hockey Pucks would not show up in network games.
+- More misc bug fixes and tidying.
+
+### 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.
+- Misc cleanup and minor bug fixes.
+
+### 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.
+- 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.
+
### 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](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
@@ -16,7 +201,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.
@@ -24,9 +209,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.
@@ -36,19 +221,22 @@
- 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..
+- 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.
### 1.4.151 (14371)
- Added Chinese-Traditional language and improved translations for others.
@@ -56,8 +244,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
@@ -95,7 +283,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
@@ -215,10 +403,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
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 78e21e1b..5ab7328e 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -9,9 +9,14 @@
- Fixed some game modes
### Roman Trapeznikov
-###### Ballistica
-- Bug fixes
-###### beyond the project code
-- Game servers developer
-- Modder
+- Bug fixes and code cleanup
+### Benefit-Zebra
+- Unofficial BombSquad Bug Finder
+- Code Cleanup
+
+### Ali Borhani
+- Bug fixes
+
+### Mr.Smoothy
+- Modder
\ No newline at end of file
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
diff --git a/Makefile b/Makefile
index 99a72509..fea10b96 100644
--- a/Makefile
+++ b/Makefile
@@ -1,33 +1,21 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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.
# 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_"
+# Set env-var BA_ENABLE_IRONY_BUILD_DB=1 to enable creating/updating a
+# cmake compile-commands database for use with irony for emacs (and possibly
+# other tools).
+ifeq ($(BA_ENABLE_IRONY_BUILD_DB),1)
+ PREREQ_IRONY = .cache/irony/compile_commands.json
+endif
+
################################################################################
# #
@@ -37,18 +25,18 @@ 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 \
+PREREQS = .cache/checkenv $(PREREQ_IRONY) .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.
prereqs: ${PREREQS}
prereqs-clean:
- @rm -rf ${PREREQS} .irony
+ @rm -rf ${PREREQS}
# Build all assets for all platforms.
assets: prereqs
@@ -86,7 +74,30 @@ assets-android: prereqs
assets-clean:
@cd assets && ${MAKE} clean
-# Remove *ALL* files and directories that aren't managed by git
+# 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
+
+# Build our generated code.
+# TODO: should perhaps make this a more standard component, including it
+# in other standard targets such as checks and tests (at least once we're
+# generating things that can affect the outcome of said checks/tests).
+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}
@@ -98,10 +109,10 @@ clean-list:
@git clean -dnx ${ROOT_CLEAN_IGNORES}
# Tell make which of these targets don't represent files.
-.PHONY: list prereqs prereqs-clean assets assets-cmake assets-windows \
+.PHONY: help 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 code code-clean \
clean clean-list
@@ -115,337 +126,389 @@ 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
-
-# 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
- @${RUN_PREFAB_MAC_DEBUG}
-
-prefab-mac-debug-build: prereqs assets-cmake \
- build/prefab/mac/debug/ballisticacore
- @${STAGE_ASSETS} -cmake build/prefab/mac/debug
-
-build/prefab/mac/debug/ballisticacore: .efrocachemap
- @tools/snippets 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
- @${RUN_PREFAB_MAC_RELEASE}
-
-prefab-mac-release-build: prereqs assets-cmake \
- build/prefab/mac/release/ballisticacore
- @${STAGE_ASSETS} -cmake build/prefab/mac/release
-
-build/prefab/mac/release/ballisticacore: .efrocachemap
- @tools/snippets 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
- @${RUN_PREFAB_MAC_SERVER_DEBUG}
-
-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} -cmake-server build/prefab/mac-server/debug/dist
-
-build/prefab/mac-server/debug/ballisticacore_server: \
- assets/src/server/ballisticacore_server.py
- @cp $< $@
-
-build/prefab/mac-server/debug/config_template.yaml: \
- assets/src/server/config_template.yaml \
- tools/batools/build.py \
- tools/bacommon/servermanager.py
- @tools/snippets filter_server_config $< $@
-
-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 $@
-
-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
- @${RUN_PREFAB_MAC_SERVER_RELEASE}
-
-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} -cmake-server build/prefab/mac-server/release/dist
-
-build/prefab/mac-server/release/ballisticacore_server: \
- assets/src/server/ballisticacore_server.py
- @cp $< $@
-
-build/prefab/mac-server/release/config_template.yaml: \
- assets/src/server/config_template.yaml \
- tools/batools/build.py \
- tools/bacommon/servermanager.py
- @tools/snippets filter_server_config $< $@
-
-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 $@
-
-RUN_PREFAB_LINUX_DEBUG = cd build/prefab/linux/debug && ./ballisticacore
-
-prefab-linux-debug: prefab-linux-debug-build
- @tools/snippets ensure_prefab_platform linux
- @${RUN_PREFAB_LINUX_DEBUG}
-
-prefab-linux-debug-build: prereqs assets-cmake \
- build/prefab/linux/debug/ballisticacore
- @${STAGE_ASSETS} -cmake build/prefab/linux/debug
-
-build/prefab/linux/debug/ballisticacore: .efrocachemap
- @tools/snippets 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
- @${RUN_PREFAB_LINUX_RELEASE}
-
-prefab-linux-release-build: prereqs assets-cmake \
- build/prefab/linux/release/ballisticacore
- @${STAGE_ASSETS} -cmake build/prefab/linux/release
-
-build/prefab/linux/release/ballisticacore: .efrocachemap
- @tools/snippets 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
- @${RUN_PREFAB_LINUX_SERVER_DEBUG}
-
-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} -cmake-server build/prefab/linux-server/debug/dist
-
-build/prefab/linux-server/debug/ballisticacore_server: \
- assets/src/server/ballisticacore_server.py
- @cp $< $@
-
-build/prefab/linux-server/debug/config_template.yaml: \
- assets/src/server/config_template.yaml \
- tools/batools/build.py \
- tools/bacommon/servermanager.py
- @tools/snippets filter_server_config $< $@
-
-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 $@
-
-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
- @${RUN_PREFAB_LINUX_SERVER_RELEASE}
-
-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} -cmake-server build/prefab/linux-server/release/dist
-
-build/prefab/linux-server/release/ballisticacore_server: \
- assets/src/server/ballisticacore_server.py
- @cp $< $@
-
-build/prefab/linux-server/release/config_template.yaml: \
- assets/src/server/config_template.yaml \
- tools/batools/build.py \
- tools/bacommon/servermanager.py
- @tools/snippets filter_server_config $< $@
-
-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 $@
-
-PREFAB_WINDOWS_PLATFORM = x64
-
-RUN_PREFAB_WINDOWS_DEBUG = cd build/prefab/windows/debug && ./BallisticaCore.exe
-
-prefab-windows-debug: prefab-windows-debug-build
- @tools/snippets ensure_prefab_platform windows
- @{RUN_PREFAB_WINDOWS_DEBUG}
-
-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
-
-build/prefab/windows/debug/BallisticaCore.exe: .efrocachemap
- @tools/snippets 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
- @{RUN_PREFAB_WINDOWS_RELEASE}
-
-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
-
-build/prefab/windows/release/BallisticaCore.exe: .efrocachemap
- @tools/snippets 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
- @{RUN_PREFAB_WINDOWS_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} -win-$(PREFAB_WINDOWS_PLATFORM) \
- build/prefab/windows-server/debug/dist
-
-build/prefab/windows-server/debug/dist/ballisticacore_headless.exe: .efrocachemap
- @tools/snippets efrocache_get $@
-
-build/prefab/windows-server/debug/ballisticacore_server.py: \
- assets/src/server/ballisticacore_server.py
- @cp $< $@
-
-build/prefab/windows-server/debug/launch_ballisticacore_server.bat: \
- assets/src/server/launch_ballisticacore_server.bat
- @cp $< $@
-
-build/prefab/windows-server/debug/config_template.yaml: \
- assets/src/server/config_template.yaml \
- tools/batools/build.py \
- tools/bacommon/servermanager.py
- @tools/snippets filter_server_config $< $@
-
-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
-
-prefab-windows-server-release: prefab-windows-server-release-build
- @tools/snippets ensure_prefab_platform windows
- @{RUN_PREFAB_WINDOWS_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} -win-$(PREFAB_WINDOWS_PLATFORM) \
- build/prefab/windows-server/release/dist
-
-build/prefab/windows-server/release/dist/ballisticacore_headless.exe: .efrocachemap
- @tools/snippets efrocache_get $@
-
-build/prefab/windows-server/release/ballisticacore_server.py: \
- assets/src/server/ballisticacore_server.py
- @cp $< $@
-
-build/prefab/windows-server/release/launch_ballisticacore_server.bat: \
- assets/src/server/launch_ballisticacore_server.bat
- @cp $< $@
-
-build/prefab/windows-server/release/config_template.yaml: \
- assets/src/server/config_template.yaml \
- tools/batools/build.py \
- tools/bacommon/servermanager.py
- @tools/snippets filter_server_config $< $@
-
-build/prefab/windows-server/release/README.txt: \
- assets/src/server/README.txt
- @cp $< $@
+ @tools/pcommand make_prefab server-release
+# Clean all prefab builds.
prefab-clean:
rm -rf build/prefab
+# Specific platform prefab targets:
+
+# (what visual studio calls their x86 target platform)
+WINPLAT_X86 = Win32
+
+# Mac debug:
+
+RUN_PREFAB_MAC_X86_64_DEBUG = cd build/prefab/full/mac_x86_64/debug \
+ && ./ballisticacore
+
+RUN_PREFAB_MAC_ARM64_DEBUG = cd build/prefab/full/mac_arm64/debug \
+ && ./ballisticacore
+
+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}
+
+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/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/full/mac_arm64/debug/ballisticacore
+ @${STAGE_ASSETS} -cmake build/prefab/full/mac_arm64/debug
+
+build/prefab/full/mac_%/debug/ballisticacore: .efrocachemap
+ @tools/pcommand efrocache_get $@
+
+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
+
+RUN_PREFAB_MAC_ARM64_RELEASE = cd build/prefab/full/mac_arm64/release \
+ && ./ballisticacore
+
+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}
+
+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/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/full/mac_arm64/release/ballisticacore
+ @${STAGE_ASSETS} -cmake build/prefab/full/mac_arm64/release
+
+build/prefab/full/mac_%/release/ballisticacore: .efrocachemap
+ @tools/pcommand efrocache_get $@
+
+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
+
+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
+ @${RUN_PREFAB_MAC_X86_64_SERVER_DEBUG}
+
+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/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
+ @${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 $@
+
+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
+
+RUN_PREFAB_MAC_ARM64_SERVER_RELEASE = cd \
+ 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
+ @${RUN_PREFAB_MAC_X86_64_SERVER_RELEASE}
+
+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/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
+ @${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 $@
+
+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
+
+RUN_PREFAB_LINUX_ARM64_DEBUG = cd \
+ 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
+ @${RUN_PREFAB_LINUX_X86_64_DEBUG}
+
+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/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/full/linux_arm64/debug/ballisticacore
+ @${STAGE_ASSETS} -cmake build/prefab/full/linux_arm64/debug
+
+build/prefab/full/linux_%/debug/ballisticacore: .efrocachemap
+ @tools/pcommand efrocache_get $@
+
+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
+
+RUN_PREFAB_LINUX_ARM64_RELEASE = cd \
+ 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
+ @${RUN_PREFAB_LINUX_X86_64_RELEASE}
+
+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/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/full/linux_arm64/release/ballisticacore
+ @${STAGE_ASSETS} -cmake build/prefab/full/linux_arm64/release
+
+build/prefab/full/linux_%/release/ballisticacore: .efrocachemap
+ @tools/pcommand efrocache_get $@
+
+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
+
+RUN_PREFAB_LINUX_ARM64_SERVER_DEBUG = cd \
+ 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
+ @${RUN_PREFAB_LINUX_X86_64_SERVER_DEBUG}
+
+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/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
+ @${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 $@
+
+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
+
+RUN_PREFAB_LINUX_ARM64_SERVER_RELEASE = cd \
+ 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-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
+ @${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
+ @${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 $@
+
+build/prefab/lib/linux_%_server/release/libballisticacore_internal.a: .efrocachemap
+ @tools/pcommand efrocache_get $@
+
+# Windows debug:
+
+RUN_PREFAB_WINDOWS_X86_DEBUG = cd build/prefab/full/windows_x86/debug \
+ && ./BallisticaCore.exe
+
+prefab-windows-x86-debug: prefab-windows-x86-debug-build
+ @tools/pcommand ensure_prefab_platform windows_x86
+ @{RUN_PREFAB_WINDOWS_X86_DEBUG}
+
+prefab-windows-x86-debug-build: prereqs assets-windows-${WINPLAT_X86} \
+ build/prefab/full/windows_x86/debug/BallisticaCore.exe
+ @${STAGE_ASSETS} -win-${WINPLAT_X86}-Debug \
+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
+
+prefab-windows-x86-release: prefab-windows-x86-release-build
+ @tools/pcommand ensure_prefab_platform windows_x86
+ @{RUN_PREFAB_WINDOWS_X86_RELEASE}
+
+prefab-windows-x86-release-build: prereqs \
+ assets-windows-${WINPLAT_X86} \
+ build/prefab/full/windows_x86/release/BallisticaCore.exe
+ @${STAGE_ASSETS} -win-${WINPLAT_X86}-Release \
+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
+
+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-x86-server-debug-build: prereqs \
+ assets-windows-${WINPLAT_X86} \
+ build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe
+ @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Debug \
+ build/prefab/full/windows_x86_server/debug
+
+build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe: .efrocachemap
+ @tools/pcommand efrocache_get $@
+
+# Windows server release:
+
+RUN_PREFAB_WINDOWS_X86_SERVER_RELEASE = cd \
+ 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
+ @tools/pcommand ensure_prefab_platform windows_x86
+ @{RUN_PREFAB_WINDOWS_X86_SERVER_RELEASE}
+
+prefab-windows-x86-server-release-build: prereqs \
+ assets-windows-${WINPLAT_X86} \
+ build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe
+ @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Release \
+ build/prefab/full/windows_x86_server/release
+
+build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe: .efrocachemap
+ @tools/pcommand efrocache_get $@
+
# 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-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 \
+ prefab-windows-x86-server-release prefab-windows-x86-server-release-build
################################################################################
@@ -456,11 +519,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
@@ -475,32 +538,32 @@ 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/pcommand echo BLD 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/pcommand echo BLD 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
@@ -515,62 +578,62 @@ format-makefile: prereqs
# Run all project checks. (static analysis)
check: update-check
@${MAKE} -j3 cpplint pylint mypy
- @echo ALL CHECKS PASSED!
+ @tools/pcommand echo SGRN BLD 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/pcommand echo SGRN BLD 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/pcommand echo SGRN BLD 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/pcommand echo SGRN BLD 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 \
@@ -586,20 +649,27 @@ pycharm-full: prereqs
# Run all tests. (live execution verification)
test: prereqs
- @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.
+# Individual test with extra 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 -vv \
tests/test_ba/test_assetmanager.py::test_assetmanager
+# Individual test with extra output enabled.
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 -vv \
tests/test_efro/test_dataclasses.py
+# Individual test with extra output enabled.
+test-entity:
+ @tools/pcommand pytest -o log_cli=true -o log_cli_level=debug -s -vv \
+ tests/test_efro/test_entity.py
+
# Tell make which of these targets don't represent files.
.PHONY: test test-full test-assetmanager
@@ -615,33 +685,83 @@ preflight:
@${MAKE} format
@${MAKE} update
@${MAKE} -j4 cpplint pylint mypy test
- @echo 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
- @echo 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
- @echo 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
- @echo 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
+################################################################################
+# #
+# CMake #
+# #
+################################################################################
+
+# Set the following from the command line to influence the build:
+
+# This can be Debug or Release.
+CMAKE_BUILD_TYPE ?= Debug
+
+# Build and run the cmake build.
+cmake: cmake-build
+ @cd build/cmake/$(CM_BT_LC) && ./ballisticacore
+
+# 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_cmake_prefab_lib standard ${CM_BT_LC} 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) \
+ ${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_server
+
+cmake-server-build: assets-cmake resources code
+ @tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC)/dist
+ @tools/pcommand update_cmake_prefab_lib server ${CM_BT_LC} 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)/dist && test -f Makefile \
+ || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true \
+ ${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)
+
+# 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 #
@@ -656,53 +776,89 @@ 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 \
--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} $< $@
+ @${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} $< $@
+
+# Set this to 1 to skip environment checks.
+SKIP_ENV_CHECKS ?= 0
-# Include anything as sources here that should require
.cache/checkenv: ${ENV_SRC}
- @tools/snippets checkenv
- @mkdir -p .cache
- @touch .cache/checkenv
+ @if [ ${SKIP_ENV_CHECKS} -ne 1 ]; then \
+ tools/pcommand checkenv && mkdir -p .cache && touch .cache/checkenv; \
+ fi
+
+# 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 .
+
+# Simple target for CI to build a binary but not download/assemble assets/etc.
+_cmake-simple-ci-server-build:
+ SKIP_ENV_CHECKS=1 ${MAKE} code
+ rm -rf build/cmake_simple_ci_server_build
+ mkdir -p build/cmake_simple_ci_server_build
+ tools/pcommand update_cmake_prefab_lib \
+ server debug build/cmake_simple_ci_server_build
+ cd build/cmake_simple_ci_server_build && \
+ cmake -DCMAKE_BUILD_TYPE=Debug -DHEADLESS=true ${PWD}/ballisticacore-cmake
+ cd build/cmake_simple_ci_server_build && ${MAKE} -j${CPUS}
+
+# Irony in emacs requires us to use cmake to generate a full
+# list of compile commands for all files; lets try to keep it up to date
+# whenever CMakeLists changes.
+.cache/irony/compile_commands.json: ballisticacore-cmake/CMakeLists.txt
+ @tools/pcommand echo BLU Updating Irony build commands db...
+ @echo Generating Irony compile-commands-list...
+ @mkdir -p .cache/irony
+ @cd .cache/irony \
+ && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug \
+ ${PWD}/ballisticacore-cmake
+ @mv .cache/irony/compile_commands.json . \
+ && rm -rf .cache/irony \
+ && mkdir .cache/irony \
+ && mv compile_commands.json .cache/irony
+ @tools/pcommand echo BLU Created Irony build db at $@
# Tell make which of these targets don't represent files.
-.PHONY:
+.PHONY: _cmake-simple-ci-server-build
diff --git a/README.md b/README.md
index bf2b990d..e84378f9 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.
+* A: Yes and no. All code contained in this repo is MIT licensed and free for use anywhere. This includes game scripts, pipeline tools, and most 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 libraries/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/.asset_manifest_private.json b/assets/.asset_manifest_private.json
index 8da5c579..d96286e2 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",
@@ -939,26 +940,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",
@@ -1687,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",
@@ -2577,175 +2582,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 +2772,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 +2809,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 +2820,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 +2845,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 +2868,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 +2903,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 +2939,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 +2961,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 +3109,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 +3195,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 +3224,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 +3242,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 +3274,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 +3331,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 +3367,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 +3386,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 +3407,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 +3630,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 +3667,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 +3678,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 +3703,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 +3726,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 +3761,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 +3797,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 +3819,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 +3967,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 +4053,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 +4082,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 +4100,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 +4132,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 +4189,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 +4225,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 +4244,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 +4265,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 +4548,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 +4585,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 +4596,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 +4621,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 +4644,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 +4719,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 +4741,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 +4889,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 +4975,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 +4986,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 +5004,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 +5054,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 +5098,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 +5112,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 +5119,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 +5152,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 +5168,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,244 +5195,283 @@
"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/VC_redist.x86.exe",
"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/python38.dll",
+ "windows/Win32/python38_d.dll",
+ "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",
+ "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",
@@ -5890,31 +5493,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",
@@ -5922,6 +5530,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",
@@ -5932,10 +5541,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",
@@ -5955,18 +5566,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",
@@ -5978,372 +5589,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",
@@ -6361,15 +5664,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",
@@ -6383,131 +5686,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",
@@ -6533,7 +5834,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",
@@ -6620,7 +5920,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",
@@ -6632,14 +5931,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",
@@ -6658,47 +5949,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",
@@ -6707,69 +5999,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",
@@ -6796,11 +6043,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",
@@ -6815,7 +6057,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",
@@ -6823,31 +6064,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",
@@ -6876,94 +6097,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",
@@ -6971,47 +6113,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",
@@ -7022,43 +6140,51 @@
"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/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/python38.dll",
+ "windows/x64/python38_d.dll",
+ "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"
]
\ No newline at end of file
diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json
index f90691dc..c5603603 100644
--- a/assets/.asset_manifest_public.json
+++ b/assets/.asset_manifest_public.json
@@ -1,70 +1,84 @@
[
"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__/_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__/_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__/_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",
- "ba_data/python/ba/__pycache__/_nodeactor.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",
- "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",
- "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__/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__/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__/_ads.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__/_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",
+ "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__/_keyboard.cpython-38.opt-1.pyc",
+ "ba_data/python/ba/__pycache__/_language.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",
"ba_data/python/ba/_activitytypes.py",
"ba_data/python/ba/_actor.py",
+ "ba_data/python/ba/_ads.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",
+ "ba_data/python/ba/_appmode.py",
"ba_data/python/ba/_apputils.py",
"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",
@@ -78,60 +92,69 @@
"ba_data/python/ba/_general.py",
"ba_data/python/ba/_hooks.py",
"ba_data/python/ba/_input.py",
- "ba_data/python/ba/_lang.py",
+ "ba_data/python/ba/_keyboard.py",
+ "ba_data/python/ba/_language.py",
"ba_data/python/ba/_level.py",
"ba_data/python/ba/_lobby.py",
"ba_data/python/ba/_map.py",
"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",
"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",
"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",
"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",
+ "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__/net.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/net.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__/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",
@@ -141,27 +164,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",
@@ -184,25 +207,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",
@@ -221,26 +244,31 @@
"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/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-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",
@@ -260,58 +288,57 @@
"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__/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",
@@ -325,10 +352,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",
@@ -336,16 +363,27 @@
"ba_data/python/bastd/ui/debug.py",
"ba_data/python/bastd/ui/feedback.py",
"ba_data/python/bastd/ui/fileselector.py",
- "ba_data/python/bastd/ui/gather.py",
+ "ba_data/python/bastd/ui/gather/__init__.py",
+ "ba_data/python/bastd/ui/gather/__pycache__/__init__.cpython-38.opt-1.pyc",
+ "ba_data/python/bastd/ui/gather/__pycache__/abouttab.cpython-38.opt-1.pyc",
+ "ba_data/python/bastd/ui/gather/__pycache__/manualtab.cpython-38.opt-1.pyc",
+ "ba_data/python/bastd/ui/gather/__pycache__/nearbytab.cpython-38.opt-1.pyc",
+ "ba_data/python/bastd/ui/gather/__pycache__/privatetab.cpython-38.opt-1.pyc",
+ "ba_data/python/bastd/ui/gather/__pycache__/publictab.cpython-38.opt-1.pyc",
+ "ba_data/python/bastd/ui/gather/abouttab.py",
+ "ba_data/python/bastd/ui/gather/manualtab.py",
+ "ba_data/python/bastd/ui/gather/nearbytab.py",
+ "ba_data/python/bastd/ui/gather/privatetab.py",
+ "ba_data/python/bastd/ui/gather/publictab.py",
"ba_data/python/bastd/ui/getcurrency.py",
"ba_data/python/bastd/ui/getremote.py",
"ba_data/python/bastd/ui/helpui.py",
"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",
@@ -354,15 +392,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",
@@ -374,10 +412,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",
@@ -389,24 +427,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__/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",
@@ -417,6 +456,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",
@@ -425,21 +465,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",
@@ -452,23 +492,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",
@@ -479,6 +519,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 0aeb2198..ac33b73b 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 #
@@ -42,45 +24,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
@@ -139,457 +121,502 @@ 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-38.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 = \
- 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/_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/__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/_freeforallsession.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/_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/_ads.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/_appmode.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/_keyboard.py \
+ build/ba_data/python/ba/_language.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/_multiteamsession.py \
build/ba_data/python/ba/_music.py \
- build/ba_data/python/ba/_lang.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/_plugin.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/_settings.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/_ui.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/modutils.py \
+ build/ba_data/python/ba/osmusic.py \
build/ba_data/python/ba/ui/__init__.py \
- build/ba_data/python/bastd/mainmenu.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/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/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 \
+ 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/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/__init__.py \
+ build/ba_data/python/bastd/ui/gather/abouttab.py \
+ build/ba_data/python/bastd/ui/gather/manualtab.py \
+ build/ba_data/python/bastd/ui/gather/nearbytab.py \
+ build/ba_data/python/bastd/ui/gather/privatetab.py \
+ build/ba_data/python/bastd/ui/gather/publictab.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/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 \
+ 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__/_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__/__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__/_freeforallsession.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__/_lang.cpython-37.opt-1.pyc \
- 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__/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/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__/characterpicker.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/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/profile/__pycache__/__init__.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/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/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__/_ads.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__/_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 \
+ 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__/_keyboard.cpython-38.opt-1.pyc \
+ build/ba_data/python/ba/__pycache__/_language.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/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 \
+ 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/gather/__pycache__/__init__.cpython-38.opt-1.pyc \
+ build/ba_data/python/bastd/ui/gather/__pycache__/abouttab.cpython-38.opt-1.pyc \
+ build/ba_data/python/bastd/ui/gather/__pycache__/manualtab.cpython-38.opt-1.pyc \
+ build/ba_data/python/bastd/ui/gather/__pycache__/nearbytab.cpython-38.opt-1.pyc \
+ build/ba_data/python/bastd/ui/gather/__pycache__/privatetab.cpython-38.opt-1.pyc \
+ build/ba_data/python/bastd/ui/gather/__pycache__/publictab.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)
@@ -600,1165 +627,52 @@ $(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/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__/_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__/__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__/_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__/_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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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__/_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/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__/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__/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/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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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__/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/__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__/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__/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/__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__/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/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/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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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/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/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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @echo Compiling script: $^
- @rm -rf $@ && $(TOOLS_DIR)/snippets 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/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/net.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__/__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__/net.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)
@@ -1769,18342 +683,6348 @@ $(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/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: $^
- @rm -rf $@ && $(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 $@
-
-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 $@
-
+# 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")
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/__main__.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/exceptions.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/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 \
+ 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/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/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/metadata.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/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 \
+ build/pylib-apple/zipimport.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__/__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__/_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__/_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__/binhex.cpython-37.opt-1.pyc \
- build/pylib-apple/__pycache__/plistlib.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__/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__/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__/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__/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/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/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__/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__/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__/headerregistry.cpython-37.opt-1.pyc \
- build/pylib-apple/email/mime/__pycache__/multipart.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__/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/__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)
$(SCRIPT_TARGETS_PY_PRIVATE_APPLE) : ../.efrocachemap
- @cd .. && tools/snippets 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__/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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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 $@
-
-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__/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/__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/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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/__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/__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/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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 $@
-
-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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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
- @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
- @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/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/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/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
- @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
- @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
- @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
- @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
- @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
- @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/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/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/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
- @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/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
- @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
- @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/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/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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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
- @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
- @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
- @echo Compiling script: $^
- @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
+ @cd .. && tools/pcommand efrocache_get assets/$@
+# 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/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/__main__.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/exceptions.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/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 \
+ 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/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/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/metadata.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/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 \
+ build/pylib-android/zipimport.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__/__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__/_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__/_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__/binhex.cpython-37.opt-1.pyc \
- build/pylib-android/__pycache__/plistlib.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__/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__/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__/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__/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/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/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__/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__/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__/headerregistry.cpython-37.opt-1.pyc \
- build/pylib-android/email/mime/__pycache__/multipart.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__/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/__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)
$(SCRIPT_TARGETS_PY_PRIVATE_ANDROID) : ../.efrocachemap
- @cd .. && tools/snippets 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__/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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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 $@
-
-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__/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/__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/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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/__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/__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/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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 $@
-
-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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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
- @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
- @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/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/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/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
- @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
- @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
- @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
- @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
- @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
- @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/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/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/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
- @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/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
- @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
- @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/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/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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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
- @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
- @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
- @echo Compiling script: $^
- @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
+ @cd .. && tools/pcommand efrocache_get assets/$@
+# 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 \
- 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__/cyaml.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__/resolver.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/__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)
$(SCRIPT_TARGETS_PY_PRIVATE_COMMON) : ../.efrocachemap
- @cd .. && tools/snippets 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 $@ && $(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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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__/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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 $@
-
-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 $@
-
-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 $@
-
-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__/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 $@
-
-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
- @echo Compiling script: $^
- @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
+ @cd .. && tools/pcommand efrocache_get assets/$@
+# 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/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/ctypes/__init__.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/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/test_anon.py \
- build/windows/Win32/Lib/ctypes/test/test_init.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_objects.py \
- build/windows/Win32/Lib/ctypes/test/test_sizes.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/curses/__init__.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/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/importlib/__init__.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_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/__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 \
+ 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/exceptions.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/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 \
+ 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/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/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/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/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/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/curses/textpad.py \
+ build/windows/Win32/Lib/dataclasses.py \
+ build/windows/Win32/Lib/datetime.py \
+ build/windows/Win32/Lib/decimal.py \
+ build/windows/Win32/Lib/difflib.py \
+ build/windows/Win32/Lib/dis.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/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/_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/iterators.py \
- build/windows/Win32/Lib/email/quoprimime.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/_parseaddr.py \
- build/windows/Win32/Lib/email/base64mime.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/mime/multipart.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/message.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/mime/audio.py \
- build/windows/Win32/Lib/email/mime/image.py \
- build/windows/Win32/Lib/email/mime/base.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/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/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/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/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/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 \
+ 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/lzma.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/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/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/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/types.py \
+ build/windows/Win32/Lib/typing.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/warnings.py \
+ build/windows/Win32/Lib/wave.py \
+ build/windows/Win32/Lib/weakref.py \
+ build/windows/Win32/Lib/webbrowser.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 \
+ build/windows/Win32/Lib/zipimport.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__/__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__/_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__/_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__/binhex.cpython-37.opt-1.pyc \
- build/windows/Win32/Lib/__pycache__/plistlib.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__/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__/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__/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__/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/ctypes/__pycache__/__init__.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/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__/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_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_objects.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_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/curses/__pycache__/__init__.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/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/importlib/__pycache__/__init__.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/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/__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)
$(SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32) : ../.efrocachemap
- @cd .. && tools/snippets 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__/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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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 $@
-
-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__/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/__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/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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/__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/__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/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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 $@
-
-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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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/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/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
- @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/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
- @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
- @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
- @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/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
- @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
- @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
- @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
- @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/__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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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
- @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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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
- @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
- @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
- @echo Compiling script: $^
- @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
+ @cd .. && tools/pcommand efrocache_get assets/$@
+# 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/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/ctypes/__init__.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/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/test_anon.py \
- build/windows/x64/Lib/ctypes/test/test_init.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_objects.py \
- build/windows/x64/Lib/ctypes/test/test_sizes.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/curses/__init__.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/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/importlib/__init__.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_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/__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 \
+ 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/exceptions.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/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 \
+ 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/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/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/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/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/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/curses/textpad.py \
+ build/windows/x64/Lib/dataclasses.py \
+ build/windows/x64/Lib/datetime.py \
+ build/windows/x64/Lib/decimal.py \
+ build/windows/x64/Lib/difflib.py \
+ build/windows/x64/Lib/dis.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/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/_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/iterators.py \
- build/windows/x64/Lib/email/quoprimime.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/_parseaddr.py \
- build/windows/x64/Lib/email/base64mime.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/mime/multipart.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/message.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/mime/audio.py \
- build/windows/x64/Lib/email/mime/image.py \
- build/windows/x64/Lib/email/mime/base.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/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/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/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/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/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 \
+ 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/lzma.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/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/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/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/types.py \
+ build/windows/x64/Lib/typing.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/warnings.py \
+ build/windows/x64/Lib/wave.py \
+ build/windows/x64/Lib/weakref.py \
+ build/windows/x64/Lib/webbrowser.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 \
+ build/windows/x64/Lib/zipimport.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__/__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__/_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__/_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__/binhex.cpython-37.opt-1.pyc \
- build/windows/x64/Lib/__pycache__/plistlib.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__/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__/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__/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__/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/ctypes/__pycache__/__init__.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/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__/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_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_objects.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_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/curses/__pycache__/__init__.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/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/importlib/__pycache__/__init__.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/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/__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)
$(SCRIPT_TARGETS_PY_PRIVATE_WIN_X64) : ../.efrocachemap
- @cd .. && tools/snippets 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__/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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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 $@
-
-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__/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/__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/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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/__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/__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/__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
- @echo Compiling script: $^
- @rm -rf $@ && $(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 $@
-
-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/__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 $@
-
-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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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__/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/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/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/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/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/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/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/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/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/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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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/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/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
- @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/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
- @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
- @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
- @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/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
- @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
- @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
- @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
- @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/__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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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
- @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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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/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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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
- @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/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
- @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
- @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
- @echo Compiling script: $^
- @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
+ @cd .. && tools/pcommand efrocache_get assets/$@
+# 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/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/venetian.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/iircadeLogo.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/iircadeLogo.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/iircadeLogo.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/iircadeLogo_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/_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/_multiprocessing.pyd \
- build/windows/Win32/DLLs/pyexpat.pyd \
- build/windows/Win32/DLLs/_sqlite3.pyd \
- build/windows/Win32/DLLs/_queue.pyd \
- build/windows/Win32/DLLs/_socket.pyd \
- build/windows/Win32/DLLs/pyd.ico \
- build/windows/Win32/DLLs/py.ico \
- build/windows/Win32/DLLs/_ctypes.pyd \
- build/windows/Win32/DLLs/pyc.ico \
+ build/windows/Win32/DLLs/_asyncio_d.pyd \
build/windows/Win32/DLLs/_bz2.pyd \
- build/windows/Win32/DLLs/select.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/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/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/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/site-packages/README.txt \
- 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/email/architecture.rst \
+ build/windows/Win32/OpenAL32.dll \
+ 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/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/ucrtbased.dll \
+ build/windows/Win32/vc_redist.x86.exe \
+ build/windows/Win32/vcruntime140d.dll
# 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 = \
- 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/_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/_multiprocessing.pyd \
- build/windows/x64/DLLs/pyexpat.pyd \
- build/windows/x64/DLLs/_sqlite3.pyd \
- build/windows/x64/DLLs/_queue.pyd \
- build/windows/x64/DLLs/_socket.pyd \
- build/windows/x64/DLLs/pyd.ico \
- build/windows/x64/DLLs/py.ico \
- build/windows/x64/DLLs/_ctypes.pyd \
- build/windows/x64/DLLs/pyc.ico \
+ build/windows/x64/DLLs/_asyncio_d.pyd \
build/windows/x64/DLLs/_bz2.pyd \
- build/windows/x64/DLLs/select.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/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/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/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/site-packages/README.txt \
- 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/email/architecture.rst \
+ build/windows/x64/OpenAL32.dll \
+ build/windows/x64/SDL2.dll \
+ 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/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/ucrtbased.dll \
+ 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
- @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/$@
+src/ba_data/%.tex2d.png : ../.efrocachemap
+ @cd .. && tools/pcommand efrocache_get assets/$@
-src/%_+x.tex2d.png : ../.efrocachemap
- @cd .. && tools/snippets efrocache_get assets/$@
+src/ba_data/%_+x.tex2d.png : ../.efrocachemap
+ @cd .. && tools/pcommand efrocache_get assets/$@
-build/%_preview.png : ../.efrocachemap
- @cd .. && tools/snippets efrocache_get assets/$@
+build/ba_data/%_preview.png : ../.efrocachemap
+ @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:
@@ -20167,9 +7087,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/scripts
+ 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)
@@ -20180,7 +7103,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
@@ -20189,5 +7113,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/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py
index e73d0521..363d5302 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
@@ -33,9 +15,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=233656876767477563471907026700832716822
-
# I'm sorry Pylint. I know this file saddens you. Be strong.
# pylint: disable=useless-suppression
# pylint: disable=unnecessary-pass
@@ -51,16 +30,18 @@ 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)
+ List, Type, Literal)
from ba._app import App
import ba
+_T = TypeVar('_T')
+
app: App
@@ -73,13 +54,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
@@ -88,6 +62,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
@@ -146,11 +127,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.
@@ -207,13 +188,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.
@@ -253,13 +234,15 @@ 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.
- player: Optional[ba.Player]
+ 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.
client_id: int
@@ -290,9 +273,9 @@ class InputDevice:
client.
"""
- exists: bool
allows_configuring: bool
- player: Optional[ba.Player]
+ has_meaningful_button_names: bool
+ player: Optional[ba.SessionPlayer]
client_id: int
name: str
unique_identifier: str
@@ -301,6 +284,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
@@ -313,16 +303,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
@@ -521,7 +516,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)))
@@ -560,14 +555,16 @@ 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)
+ 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)
@@ -608,6 +605,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
@@ -622,12 +620,17 @@ 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
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
@@ -641,13 +644,34 @@ 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
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
@@ -677,8 +701,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
@@ -695,21 +719,35 @@ class Node:
"""
return bool()
- def get_name(self) -> str:
- """get_name() -> str
+ # Show that ur return type varies based on "doraise" value:
+ @overload
+ def getdelegate(self,
+ type: Type[_T],
+ doraise: Literal[False] = False) -> Optional[_T]:
+ ...
+
+ @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
+ ba.DelegateNotFoundError will be raised instead.
+ """
+ return None
+
+ def getname(self) -> str:
+ """getname() -> str
Return the name assigned to a Node; used mainly for debugging
"""
return str()
- def getdelegate(self) -> Any:
- """getdelegate() -> Any
-
- Returns the node's current delegate, which is the Python object
- designated to handle the Node's messages.
- """
- return _uninferrable()
-
def getnodetype(self) -> str:
"""getnodetype() -> str
@@ -737,35 +775,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() method (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.
-
- exists: bool
- Whether the player still exists.
- Most functionality will fail on a nonexistent player.
+ id: 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
@@ -775,24 +814,17 @@ 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.
+ 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.
-
- 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.
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,33 +834,35 @@ class Player:
character: str
The character this player has selected in their profile.
+
+ activityplayer: Optional[ba.Player]
+ The current game-specific instance for this player.
"""
- actor: Optional[ba.Actor]
- node: Optional[ba.Node]
- exists: bool
+ id: int
in_game: bool
- team: ba.Team
- sessiondata: Dict
- gamedata: Dict
+ sessionteam: ba.SessionTeam
+ inputdevice: ba.InputDevice
color: Sequence[float]
highlight: Sequence[float]
character: str
+ activityplayer: 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[ba.InputType, Tuple[ba.InputType, ...]],
+ call: Callable) -> None:
+ """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
+ 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
@@ -855,37 +889,14 @@ 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
-
- 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
+ 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 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
@@ -893,43 +904,13 @@ class Player:
"""
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_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
-
- (internal)
- """
- return None
-
def set_icon_info(self, texture: str, tint_texture: str,
tint_color: Sequence[float],
tint2_color: Sequence[float]) -> None:
@@ -940,11 +921,27 @@ class Player:
"""
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.
@@ -953,26 +950,14 @@ class Player:
"""
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)
"""
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.
@@ -1011,7 +996,7 @@ class Timer:
time: length of time (in seconds by default) that the timer will wait
before firing. Note that the actual delay experienced may vary
- depending on the timetype. (see below)
+ depending on the timetype. (see below)
call: A callable Python object. Note that the timer will retain a
strong reference to the callable for as long as it exists, so you
@@ -1021,28 +1006,11 @@ class Timer:
repeat: if True, the timer will fire repeatedly, with each successive
firing having the same delay as the first.
- timetype can be either 'sim', 'base', or 'real'. It defaults to
- 'sim'. Types are explained below:
+ timetype: A ba.TimeType value determining which timeline the timer is
+ placed onto.
- 'sim' time maps to local simulation time in ba.Activity or ba.Session
- Contexts. This means that it may progress slower in slow-motion play
- modes, stop when the game is paused, etc. This time type is not
- available in UI contexts.
-
- 'base' time is also linked to gameplay in ba.Activity or ba.Session
- Contexts, but it progresses at a constant rate regardless of
- slow-motion states or pausing. It can, however, slow down or stop
- in certain cases such as network outages or game slowdowns due to
- cpu load. Like 'sim' time, this is unavailable in UI contexts.
-
- 'real' time always maps to actual clock time with a bit of filtering
- added, regardless of Context. (the filtering prevents it from going
- backwards or jumping forward by large amounts due to the app being
- backgrounded, system time changing, etc.)
- Real time timers are currently only available in the UI context.
-
- the 'timeformat' arg defaults to SECONDS but can also be MILLISECONDS
- if you want to pass time as milliseconds.
+ timeformat: A ba.TimeFormat value determining how the passed time is
+ interpreted.
# Example: use a Timer object to print repeatedly for a few seconds:
def say_it():
@@ -1050,9 +1018,9 @@ class Timer:
def stop_saying_it():
self.t = None
ba.screenmessage('MUSHROOM MUSHROOM!')
- # create our timer; it will run as long as we hold self.t
+ # Create our timer; it will run as long as we have the self.t ref.
self.t = ba.Timer(0.3, say_it, repeat=True)
- # now fire off a one-shot timer to kill it
+ # Now fire off a one-shot timer to kill it.
ba.timer(3.89, stop_saying_it)
"""
@@ -1341,6 +1309,25 @@ def apply_config() -> None:
return None
+def appname() -> str:
+ """appname() -> str
+
+ (internal)
+ """
+ return str()
+
+
+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()
+
+
def back_press() -> None:
"""back_press() -> None
@@ -1458,6 +1445,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
@@ -1567,6 +1562,58 @@ def client_info_query_response(token: str, response: Any) -> None:
return None
+def clipboard_get_text() -> str:
+ """clipboard_get_text() -> str
+
+ Return text currently on the system clipboard.
+
+ Category: General Utility Functions
+
+ Ensure that ba.clipboard_has_text() returns True before calling
+ this function.
+ """
+ return str()
+
+
+def clipboard_has_text() -> bool:
+ """clipboard_has_text() -> bool
+
+ Return whether there is currently text on the clipboard.
+
+ Category: General Utility Functions
+
+ This will return False if no system clipboard is available; no need
+ to call ba.clipboard_available() separately.
+ """
+ return bool()
+
+
+def clipboard_is_supported() -> bool:
+ """clipboard_is_supported() -> bool
+
+ Return whether this platform supports clipboard operations at all.
+
+ Category: General Utility Functions
+
+ If this returns False, UIs should not show 'copy to clipboard'
+ buttons, etc.
+ """
+ return bool()
+
+
+def clipboard_set_text(value: str) -> None:
+ """clipboard_set_text(value: str) -> None
+
+ Copy a string to the system clipboard.
+
+ Category: General Utility Functions
+
+ Ensure that ba.clipboard_available() returns True before adding
+ buttons/etc. that make use of this functionality.
+ """
+ return None
+
+
def columnwidget(edit: ba.Widget = None,
parent: ba.Widget = None,
size: Sequence[float] = None,
@@ -1578,7 +1625,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,
@@ -1590,7 +1642,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.
@@ -1649,7 +1706,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,
@@ -1680,7 +1737,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,
@@ -1741,7 +1798,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
@@ -2011,7 +2068,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]:
@@ -2057,27 +2114,11 @@ def get_idle_time() -> int:
(internal)
- Returns the amount of time since any game input has been processed
+ Returns the amount of time since any game input has been received.
"""
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
@@ -2086,14 +2127,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
@@ -2334,21 +2367,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({})
+ return None
def getcollidemodel(name: str) -> ba.CollideModel:
@@ -2386,6 +2429,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
@@ -2411,8 +2489,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
@@ -2422,8 +2511,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:
@@ -2567,7 +2655,10 @@ 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_up_down: 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,
@@ -2575,7 +2666,10 @@ 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_up_down: bool = None,
+ claims_tab: bool = None) -> ba.Widget
Create or edit a horizontal scroll widget.
@@ -2684,6 +2778,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
@@ -2746,6 +2848,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
@@ -2756,12 +2866,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
@@ -2892,22 +2999,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({})
-
-
def new_host_session(sessiontype: Type[ba.Session],
benchmark_type: str = None) -> None:
"""new_host_session(sessiontype: Type[ba.Session],
@@ -2926,12 +3017,28 @@ 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: Union[Node, ba.Actor] = None,
+ owner: ba.Node = None,
attrs: dict = None,
name: str = None,
delegate: Any = None) -> Node:
- """newnode(type: str, owner: Union[Node, ba.Actor] = None,
+ """newnode(type: str, owner: ba.Node = None,
attrs: dict = None, name: str = None, delegate: Any = None)
-> Node
@@ -3034,6 +3141,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
@@ -3065,8 +3188,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.
@@ -3202,18 +3328,24 @@ def restore_purchases() -> None:
return None
-def rowwidget(edit: Widget = None,
- parent: Widget = None,
+def rowwidget(edit: ba.Widget = None,
+ parent: ba.Widget = None,
size: Sequence[float] = None,
position: Sequence[float] = None,
background: bool = None,
- selected_child: Widget = None,
- visible_child: Widget = None) -> Widget:
- """rowwidget(edit: Widget =None, parent: Widget =None,
+ selected_child: ba.Widget = None,
+ visible_child: ba.Widget = None,
+ claims_left_right: bool = None,
+ claims_tab: bool = None,
+ selection_loops_to_parent: bool = None) -> ba.Widget:
+ """rowwidget(edit: ba.Widget = None, parent: ba.Widget = None,
size: Sequence[float] = None,
position: Sequence[float] = None,
- background: bool = None, selected_child: Widget = None,
- visible_child: Widget = None) -> Widget
+ background: bool = None, selected_child: ba.Widget = None,
+ visible_child: ba.Widget = None,
+ claims_left_right: bool = None,
+ claims_tab: bool = None,
+ selection_loops_to_parent: bool = None) -> ba.Widget
Create or edit a row widget.
@@ -3223,7 +3355,8 @@ def rowwidget(edit: Widget = None,
a new one is created and returned. Arguments that are not set to None
are applied to the Widget.
"""
- return Widget()
+ import ba # pylint: disable=cyclic-import
+ return ba.Widget()
def run_transactions() -> None:
@@ -3290,14 +3423,24 @@ 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_up_down: bool = None,
+ claims_tab: bool = None,
+ autoselect: 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_up_down: bool = None,
+ claims_tab: bool = None,
+ autoselect: bool = None) -> ba.Widget
Create or edit a scroll widget.
@@ -3311,6 +3454,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
@@ -3343,6 +3494,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
@@ -3652,8 +3811,8 @@ def submit_score(game: str,
return None
-def textwidget(edit: Widget = None,
- parent: Widget = None,
+def textwidget(edit: ba.Widget = None,
+ parent: ba.Widget = None,
size: Sequence[float] = None,
position: Sequence[float] = None,
text: Union[str, ba.Lstr] = None,
@@ -3664,13 +3823,13 @@ def textwidget(edit: Widget = None,
on_return_press_call: Callable[[], None] = None,
on_activate_call: Callable[[], None] = None,
selectable: bool = None,
- query: Widget = None,
+ query: ba.Widget = None,
max_chars: int = None,
color: Sequence[float] = None,
click_activate: bool = None,
on_select_call: Callable[[], None] = None,
always_highlight: bool = None,
- draw_controller: Widget = None,
+ draw_controller: ba.Widget = None,
scale: float = None,
corner_scale: float = None,
description: Union[str, ba.Lstr] = None,
@@ -3687,16 +3846,16 @@ def textwidget(edit: Widget = None,
big: bool = None,
extra_touch_border_scale: float = None,
res_scale: float = None) -> Widget:
- """textwidget(edit: Widget = None, parent: Widget = None,
+ """textwidget(edit: ba.Widget = None, parent: ba.Widget = None,
size: Sequence[float] = None, position: Sequence[float] = None,
text: Union[str, ba.Lstr] = None, v_align: str = None,
h_align: str = None, editable: bool = None, padding: float = None,
on_return_press_call: Callable[[], None] = None,
on_activate_call: Callable[[], None] = None,
- selectable: bool = None, query: Widget = None, max_chars: int = None,
+ selectable: bool = None, query: ba.Widget = None, max_chars: int = None,
color: Sequence[float] = None, click_activate: bool = None,
on_select_call: Callable[[], None] = None,
- always_highlight: bool = None, draw_controller: Widget = None,
+ always_highlight: bool = None, draw_controller: ba.Widget = None,
scale: float = None, corner_scale: float = None,
description: Union[str, ba.Lstr] = None,
transition_delay: float = None, maxwidth: float = None,
@@ -3718,11 +3877,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.
@@ -3755,7 +3938,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/__init__.py b/assets/src/ba_data/python/ba/__init__.py
index 887e2415..72792c71 100644
--- a/assets/src/ba_data/python/ba/__init__.py
+++ b/assets/src/ba_data/python/ba/__init__.py
@@ -1,90 +1,83 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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.
For many modding purposes, the bits exposed here are all you'll need.
In some specific cases you may need to pull in individual submodules instead.
"""
-
# pylint: disable=unused-import
# pylint: disable=redefined-builtin
-from _ba import (CollideModel, Context, ContextCall, Data, InputDevice,
- Material, Model, Node, Player, 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)
+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, getactivity, getcollidemodel, getmodel, getnodes, getsession,
+ getsound, gettexture, hscrollwidget, imagewidget, log, newactivity,
+ newnode, playsound, printnodes, printobjects, pushcall, quit, rowwidget,
+ safecolor, screenmessage, scrollwidget, set_analytics_screen, charstr,
+ textwidget, time, timer, open_url, widget, clipboard_is_supported,
+ clipboard_has_text, clipboard_get_text, clipboard_set_text)
from ba._activity import Activity
+from ba._plugin import PotentialPlugin, Plugin, PluginSubsystem
from ba._actor import Actor
+from ba._player import PlayerInfo, Player, EmptyPlayer, StandLocation
from ba._nodeactor import NodeActor
from ba._app import App
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._error import (UNHANDLED, print_exception, print_error, NotFoundError,
- PlayerNotFoundError, NodeNotFoundError,
- ActorNotFoundError, InputDeviceNotFoundError,
- WidgetNotFoundError, ActivityNotFoundError,
- TeamNotFoundError, SessionNotFoundError,
- DependencyError)
+from ba._enums import (TimeType, Permission, TimeFormat, SpecialChar,
+ InputType, UIScale)
+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
-from ba._lang import Lstr, setlanguage, get_valid_languages
+from ba._gameresults import GameResults
+from ba._settings import (Setting, IntSetting, FloatSetting, ChoiceSetting,
+ BoolSetting, IntChoiceSetting, FloatChoiceSetting)
+from ba._language import Lstr, LanguageSubsystem
from ba._map import Map, getmaps
from ba._session import Session
+from ba._ui import UISubsystem
from ba._servermode import ServerController
+from ba._score import ScoreType, ScoreConfig
from ba._stats import PlayerScoredMessage, PlayerRecord, Stats
-from ba._team import Team
+from ba._team import SessionTeam, Team, EmptyTeam
from ba._teamgame import TeamGameActivity
from ba._dualteamsession import DualTeamSession
-from ba._achievement import Achievement
+from ba._achievement import Achievement, AchievementSubsystem
from ba._appconfig import AppConfig
from ba._appdelegate import AppDelegate
-from ba._apputils import is_browser_likely_available
+from ba._apputils import is_browser_likely_available, garbage_collect
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._gameutils import (GameTip, animate, animate_array, show_damage_count,
+ timestring, cameraflash)
+from ba._general import (WeakCall, Call, existing, Existable,
+ verify_object_death, storagename, getclass)
+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
-from ba._messages import (OutOfBoundsMessage, DeathType, DieMessage,
- StandMessage, PickUpMessage, DropMessage,
- PickedUpMessage, DroppedMessage,
+from ba._meta import MetadataSubsystem
+from ba._messages import (UNHANDLED, OutOfBoundsMessage, DeathType, DieMessage,
+ PlayerDiedMessage, StandMessage, PickUpMessage,
+ DropMessage, PickedUpMessage, DroppedMessage,
ShouldShatterMessage, ImpactDamageMessage,
FreezeMessage, ThawMessage, HitMessage,
CelebrateMessage)
-from ba._music import setmusic, MusicPlayer, MusicType, MusicPlayMode
+from ba._music import (setmusic, MusicPlayer, MusicType, MusicPlayMode,
+ MusicSubsystem)
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/_account.py b/assets/src/ba_data/python/ba/_account.py
index 65143a64..4b8c9973 100644
--- a/assets/src/ba_data/python/ba/_account.py
+++ b/assets/src/ba_data/python/ba/_account.py
@@ -1,218 +1,267 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
import copy
+import time
from typing import TYPE_CHECKING
import _ba
if TYPE_CHECKING:
- from typing import Any, Optional, Dict, List
+ from typing import Any, Optional, Dict, List, Tuple
+ import ba
-def handle_account_gained_tickets(count: int) -> None:
- """Called when the current account has been awarded tickets.
+class AccountSubsystem:
+ """Subsystem for account handling in the app.
- (internal)
+ Category: App Classes
+
+ Access the single shared instance of this class at 'ba.app.plugins'.
"""
- from ba._lang import Lstr
- _ba.screenmessage(Lstr(resource='getTicketsWindow.receivedTicketsText',
- subs=[('${COUNT}', str(count))]),
- color=(0, 1, 0))
- _ba.playsound(_ba.getsound('cashRegister'))
+ def __init__(self) -> None:
+ self.account_tournament_list: Optional[Tuple[int, List[str]]] = None
-def cache_league_rank_data(data: Any) -> None:
- """(internal)"""
- _ba.app.league_rank_cache['info'] = copy.deepcopy(data)
+ # FIXME: should abstract/structure these.
+ self.tournament_info: Dict = {}
+ self.league_rank_cache: Dict = {}
+ self.last_post_purchase_message_time: Optional[float] = None
+ # If we try to run promo-codes due to launch-args/etc we might
+ # not be signed in yet; go ahead and queue them up in that case.
+ self.pending_promo_codes: List[str] = []
-def get_cached_league_rank_data() -> Any:
- """(internal)"""
- return _ba.app.league_rank_cache.get('info', None)
+ def on_app_launch(self) -> None:
+ """Called when the app is done bootstrapping."""
+ # Auto-sign-in to a local account in a moment if we're set to.
+ def do_auto_sign_in() -> None:
+ if _ba.app.headless_mode or _ba.app.config.get(
+ 'Auto Account State') == 'Local':
+ _ba.sign_in('Local')
-def get_league_rank_points(data: Optional[Dict[str, Any]],
- subset: str = None) -> int:
- """(internal)"""
- if data is None:
- return 0
+ _ba.pushcall(do_auto_sign_in)
- # If the data contains an achievement total, use that. otherwise calc
- # locally.
- if data['at'] is not None:
- total_ach_value = data['at']
- else:
- total_ach_value = 0
- for ach in _ba.app.achievements:
- if ach.complete:
- total_ach_value += ach.power_ranking_value
+ def on_app_resume(self) -> None:
+ """Should be called when the app is resumed."""
- trophies_total: int = (data['t0a'] * data['t0am'] +
- data['t0b'] * data['t0bm'] +
- data['t1'] * data['t1m'] +
- data['t2'] * data['t2m'] +
- data['t3'] * data['t3m'] + data['t4'] * data['t4m'])
- if subset == 'trophyCount':
- val: int = (data['t0a'] + data['t0b'] + data['t1'] + data['t2'] +
- data['t3'] + data['t4'])
- assert isinstance(val, int)
- return val
- if subset == 'trophies':
- assert isinstance(trophies_total, int)
- return trophies_total
- if subset is not None:
- raise Exception('invalid subset value: ' + str(subset))
+ # Mark our cached tourneys as invalid so anyone using them knows
+ # they might be out of date.
+ for entry in list(self.tournament_info.values()):
+ entry['valid'] = False
- if data['p']:
- pro_mult = 1.0 + float(
- _ba.get_account_misc_read_val('proPowerRankingBoost', 0.0)) * 0.01
- else:
- pro_mult = 1.0
+ def handle_account_gained_tickets(self, count: int) -> None:
+ """Called when the current account has been awarded tickets.
- # For final value, apply our pro mult and activeness-mult.
- return int((total_ach_value + trophies_total) *
- (data['act'] if data['act'] is not None else 1.0) * pro_mult)
+ (internal)
+ """
+ from ba._language import Lstr
+ _ba.screenmessage(Lstr(resource='getTicketsWindow.receivedTicketsText',
+ subs=[('${COUNT}', str(count))]),
+ color=(0, 1, 0))
+ _ba.playsound(_ba.getsound('cashRegister'))
+ def cache_league_rank_data(self, data: Any) -> None:
+ """(internal)"""
+ self.league_rank_cache['info'] = copy.deepcopy(data)
-def cache_tournament_info(info: Any) -> None:
- """(internal)"""
- from ba._enums import TimeType, TimeFormat
- for entry in info:
- cache_entry = _ba.app.tournament_info[entry['tournamentID']] = (
- copy.deepcopy(entry))
+ def get_cached_league_rank_data(self) -> Any:
+ """(internal)"""
+ return self.league_rank_cache.get('info', None)
- # Also store the time we received this, so we can adjust
- # time-remaining values/etc.
- cache_entry['timeReceived'] = _ba.time(TimeType.REAL,
- TimeFormat.MILLISECONDS)
- cache_entry['valid'] = True
+ def get_league_rank_points(self,
+ data: Optional[Dict[str, Any]],
+ subset: str = None) -> int:
+ """(internal)"""
+ if data is None:
+ return 0
+ # If the data contains an achievement total, use that. otherwise calc
+ # locally.
+ if data['at'] is not None:
+ total_ach_value = data['at']
+ else:
+ total_ach_value = 0
+ for ach in _ba.app.ach.achievements:
+ if ach.complete:
+ total_ach_value += ach.power_ranking_value
-def get_purchased_icons() -> List[str]:
- """(internal)"""
- # pylint: disable=cyclic-import
- from ba import _store
- if _ba.get_account_state() != 'signed_in':
- return []
- icons = []
- store_items = _store.get_store_items()
- for item_name, item in list(store_items.items()):
- if item_name.startswith('icons.') and _ba.get_purchased(item_name):
- icons.append(item['icon'])
- return icons
+ trophies_total: int = (data['t0a'] * data['t0am'] +
+ data['t0b'] * data['t0bm'] +
+ data['t1'] * data['t1m'] +
+ data['t2'] * data['t2m'] +
+ data['t3'] * data['t3m'] +
+ data['t4'] * data['t4m'])
+ if subset == 'trophyCount':
+ val: int = (data['t0a'] + data['t0b'] + data['t1'] + data['t2'] +
+ data['t3'] + data['t4'])
+ assert isinstance(val, int)
+ return val
+ if subset == 'trophies':
+ assert isinstance(trophies_total, int)
+ return trophies_total
+ if subset is not None:
+ raise ValueError('invalid subset value: ' + str(subset))
+ if data['p']:
+ pro_mult = 1.0 + float(
+ _ba.get_account_misc_read_val('proPowerRankingBoost',
+ 0.0)) * 0.01
+ else:
+ pro_mult = 1.0
-def ensure_have_account_player_profile() -> None:
- """
- Ensure the standard account-named player profile exists;
- creating if needed.
- """
- # This only applies when we're signed in.
- if _ba.get_account_state() != 'signed_in':
- return
+ # For final value, apply our pro mult and activeness-mult.
+ return int(
+ (total_ach_value + trophies_total) *
+ (data['act'] if data['act'] is not None else 1.0) * pro_mult)
- # If the short version of our account name currently cant be
- # displayed by the game, cancel.
- if not _ba.have_chars(_ba.get_account_display_string(full=False)):
- return
+ def cache_tournament_info(self, info: Any) -> None:
+ """(internal)"""
+ from ba._enums import TimeType, TimeFormat
+ for entry in info:
+ cache_entry = self.tournament_info[entry['tournamentID']] = (
+ copy.deepcopy(entry))
- config = _ba.app.config
- if ('Player Profiles' not in config
- or '__account__' not in config['Player Profiles']):
+ # Also store the time we received this, so we can adjust
+ # time-remaining values/etc.
+ cache_entry['timeReceived'] = _ba.time(TimeType.REAL,
+ TimeFormat.MILLISECONDS)
+ cache_entry['valid'] = True
- # Create a spaz with a nice default purply color.
+ def get_purchased_icons(self) -> List[str]:
+ """(internal)"""
+ # pylint: disable=cyclic-import
+ from ba import _store
+ if _ba.get_account_state() != 'signed_in':
+ return []
+ icons = []
+ store_items = _store.get_store_items()
+ for item_name, item in list(store_items.items()):
+ if item_name.startswith('icons.') and _ba.get_purchased(item_name):
+ icons.append(item['icon'])
+ return icons
+
+ def ensure_have_account_player_profile(self) -> None:
+ """
+ Ensure the standard account-named player profile exists;
+ creating if needed.
+
+ (internal)
+ """
+ # This only applies when we're signed in.
+ if _ba.get_account_state() != 'signed_in':
+ return
+
+ # If the short version of our account name currently cant be
+ # displayed by the game, cancel.
+ if not _ba.have_chars(_ba.get_account_display_string(full=False)):
+ return
+
+ config = _ba.app.config
+ if ('Player Profiles' not in config
+ or '__account__' not in config['Player Profiles']):
+
+ # Create a spaz with a nice default purply color.
+ _ba.add_transaction({
+ 'type': 'ADD_PLAYER_PROFILE',
+ 'name': '__account__',
+ 'profile': {
+ 'character': 'Spaz',
+ 'color': [0.5, 0.25, 1.0],
+ 'highlight': [0.5, 0.25, 1.0]
+ }
+ })
+ _ba.run_transactions()
+
+ def have_pro(self) -> bool:
+ """Return whether pro is currently unlocked."""
+
+ # Check our tickets-based pro upgrade and our two real-IAP based
+ # upgrades. Also unlock this stuff in ballistica-core builds.
+ return bool(
+ _ba.get_purchased('upgrades.pro')
+ or _ba.get_purchased('static.pro')
+ or _ba.get_purchased('static.pro_sale')
+ or 'ballistica' + 'core' == _ba.appname())
+
+ def have_pro_options(self) -> bool:
+ """Return whether pro-options are present.
+
+ This is True for owners of Pro or old installs
+ before Pro was a requirement for these.
+ """
+
+ # We expose pro options if the server tells us to
+ # (which is generally just when we own pro),
+ # or also if we've been grandfathered in or are using ballistica-core
+ # builds.
+ return self.have_pro() or bool(
+ _ba.get_account_misc_read_val_2('proOptionsUnlocked', False)
+ or _ba.app.config.get('lc14292', 0) > 1)
+
+ def show_post_purchase_message(self) -> None:
+ """(internal)"""
+ from ba._language import Lstr
+ from ba._enums import TimeType
+ cur_time = _ba.time(TimeType.REAL)
+ if (self.last_post_purchase_message_time is None
+ or cur_time - self.last_post_purchase_message_time > 3.0):
+ self.last_post_purchase_message_time = cur_time
+ with _ba.Context('ui'):
+ _ba.screenmessage(Lstr(resource='updatingAccountText',
+ fallback_resource='purchasingText'),
+ color=(0, 1, 0))
+ _ba.playsound(_ba.getsound('click01'))
+
+ def on_account_state_changed(self) -> None:
+ """(internal)"""
+ from ba._language import Lstr
+
+ # Run any pending promo codes we had queued up while not signed in.
+ if _ba.get_account_state() == 'signed_in' and self.pending_promo_codes:
+ for code in self.pending_promo_codes:
+ _ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
+ color=(0, 1, 0))
+ _ba.add_transaction({
+ 'type': 'PROMO_CODE',
+ 'expire_time': time.time() + 5,
+ 'code': code
+ })
+ _ba.run_transactions()
+ self.pending_promo_codes = []
+
+ def add_pending_promo_code(self, code: str) -> None:
+ """(internal)"""
+ from ba._language import Lstr
+ from ba._enums import TimeType
+
+ # 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
+ # few seconds.
+ if _ba.get_account_state() != 'signed_in':
+
+ def check_pending_codes() -> None:
+ """(internal)"""
+
+ # If we're still not signed in and have pending codes,
+ # inform the user that they need to sign in to use them.
+ if self.pending_promo_codes:
+ _ba.screenmessage(Lstr(resource='signInForPromoCodeText'),
+ color=(1, 0, 0))
+ _ba.playsound(_ba.getsound('error'))
+
+ self.pending_promo_codes.append(code)
+ _ba.timer(6.0, check_pending_codes, timetype=TimeType.REAL)
+ return
+ _ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
+ color=(0, 1, 0))
_ba.add_transaction({
- 'type': 'ADD_PLAYER_PROFILE',
- 'name': '__account__',
- 'profile': {
- 'character': 'Spaz',
- 'color': [0.5, 0.25, 1.0],
- 'highlight': [0.5, 0.25, 1.0]
- }
+ 'type': 'PROMO_CODE',
+ 'expire_time': time.time() + 5,
+ 'code': code
})
_ba.run_transactions()
-
-
-def have_pro() -> bool:
- """Return whether pro is currently unlocked."""
-
- # Check our tickets-based pro upgrade and our two real-IAP based upgrades.
- # Also unlock this stuff in ballistica-core builds.
- return bool(
- _ba.get_purchased('upgrades.pro') or _ba.get_purchased('static.pro')
- or _ba.get_purchased('static.pro_sale')
- or 'ballistica' + 'core' == 'ballisticacore')
-
-
-def have_pro_options() -> bool:
- """Return whether pro-options are present.
-
- This is True for owners of Pro or old installs
- before Pro was a requirement for these.
- """
-
- # We expose pro options if the server tells us to
- # (which is generally just when we own pro),
- # or also if we've been grandfathered in or are using ballistica-core
- # builds.
- return have_pro() or bool(
- _ba.get_account_misc_read_val_2('proOptionsUnlocked', False)
- or _ba.app.config.get('lc14292', 0) > 1)
-
-
-def show_post_purchase_message() -> None:
- """(internal)"""
- from ba._lang import Lstr
- from ba._enums import TimeType
- app = _ba.app
- cur_time = _ba.time(TimeType.REAL)
- if (app.last_post_purchase_message_time is None
- or cur_time - app.last_post_purchase_message_time > 3.0):
- app.last_post_purchase_message_time = cur_time
- with _ba.Context('ui'):
- _ba.screenmessage(Lstr(resource='updatingAccountText',
- fallback_resource='purchasingText'),
- color=(0, 1, 0))
- _ba.playsound(_ba.getsound('click01'))
-
-
-def on_account_state_changed() -> None:
- """(internal)"""
- import time
- from ba import _lang
- app = _ba.app
-
- # Run any pending promo codes we had queued up while not signed in.
- if _ba.get_account_state() == 'signed_in' and app.pending_promo_codes:
- for code in app.pending_promo_codes:
- _ba.screenmessage(_lang.Lstr(resource='submittingPromoCodeText'),
- color=(0, 1, 0))
- _ba.add_transaction({
- 'type': 'PROMO_CODE',
- 'expire_time': time.time() + 5,
- 'code': code
- })
- _ba.run_transactions()
- app.pending_promo_codes = []
diff --git a/assets/src/ba_data/python/ba/_achievement.py b/assets/src/ba_data/python/ba/_achievement.py
index 09445c1b..8775313e 100644
--- a/assets/src/ba_data/python/ba/_achievement.py
+++ b/assets/src/ba_data/python/ba/_achievement.py
@@ -1,32 +1,15 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
from typing import TYPE_CHECKING
import _ba
+from ba._error import print_exception
if TYPE_CHECKING:
- from typing import Any, Sequence, List, Dict, Union, Optional
+ from typing import Any, Sequence, List, Dict, Union, Optional, Tuple, Set
import ba
# This could use some cleanup.
@@ -79,69 +62,346 @@ ACH_LEVEL_NAMES = {
}
-def award_local_achievement(achname: str) -> None:
- """For non-game-based achievements such as controller-connection ones."""
- try:
- ach = get_achievement(achname)
- if not ach.complete:
+class AchievementSubsystem:
+ """Subsystem for achievement handling.
- # Report new achievements to the game-service.
- _ba.report_achievement(achname)
+ Category: App Classes
- # And to our account.
- _ba.add_transaction({'type': 'ACHIEVEMENT', 'name': achname})
-
- # Now attempt to show a banner.
- display_achievement_banner(achname)
-
- except Exception:
- from ba import _error
- _error.print_exception()
-
-
-def display_achievement_banner(achname: str) -> None:
- """Display a completion banner for an achievement.
-
- Used for server-driven achievements.
+ Access the single shared instance of this class at 'ba.app.ach'.
"""
- try:
- # FIXME: Need to get these using the UI context or some other
- # purely local context somehow instead of trying to inject these
- # into whatever activity happens to be active
- # (since that won't work while in client mode).
- activity = _ba.get_foreground_host_activity()
- if activity is not None:
- with _ba.Context(activity):
- get_achievement(achname).announce_completion()
- except Exception:
- from ba import _error
- _error.print_exception('error showing server ach')
+ def __init__(self) -> None:
+ self.achievements: List[Achievement] = []
+ self.achievements_to_display: (List[Tuple[ba.Achievement, bool]]) = []
+ self.achievement_display_timer: Optional[_ba.Timer] = None
+ self.last_achievement_display_time: float = 0.0
+ self.achievement_completion_banner_slots: Set[int] = set()
+ self._init_achievements()
-# This gets called whenever game-center/game-circle/etc tells us which
-# achievements we currently have. We always defer to them, even if that
-# means we have to un-set an achievement we think we have
+ def _init_achievements(self) -> None:
+ """Fill in available achievements."""
+ achs = self.achievements
-def set_completed_achievements(achs: Sequence[str]) -> None:
- """Set the current state of completed achievements.
+ # 5
+ achs.append(
+ Achievement('In Control', 'achievementInControl', (1, 1, 1), '',
+ 5))
+ # 15
+ achs.append(
+ Achievement('Sharing is Caring', 'achievementSharingIsCaring',
+ (1, 1, 1), '', 15))
+ # 10
+ achs.append(
+ Achievement('Dual Wielding', 'achievementDualWielding', (1, 1, 1),
+ '', 10))
- All achievements not included here will be set incomplete.
- """
- cfg = _ba.app.config
- cfg['Achievements'] = {}
- for a_name in achs:
- get_achievement(a_name).set_complete(True)
- cfg.commit()
+ # 10
+ achs.append(
+ Achievement('Free Loader', 'achievementFreeLoader', (1, 1, 1), '',
+ 10))
+ # 20
+ achs.append(
+ Achievement('Team Player', 'achievementTeamPlayer', (1, 1, 1), '',
+ 20))
+ # 5
+ achs.append(
+ Achievement('Onslaught Training Victory', 'achievementOnslaught',
+ (1, 1, 1), 'Default:Onslaught Training', 5))
+ # 5
+ achs.append(
+ Achievement('Off You Go Then', 'achievementOffYouGo',
+ (1, 1.1, 1.3), 'Default:Onslaught Training', 5))
+ # 10
+ achs.append(
+ Achievement('Boxer',
+ 'achievementBoxer', (1, 0.6, 0.6),
+ 'Default:Onslaught Training',
+ 10,
+ hard_mode_only=True))
-def get_achievement(name: str) -> Achievement:
- """Return an Achievement by name."""
- achs = [a for a in _ba.app.achievements if a.name == name]
- assert len(achs) < 2
- if not achs:
- raise Exception("Invalid achievement name: '" + name + "'")
- return achs[0]
+ # 10
+ achs.append(
+ Achievement('Rookie Onslaught Victory', 'achievementOnslaught',
+ (0.5, 1.4, 0.6), 'Default:Rookie Onslaught', 10))
+ # 10
+ achs.append(
+ Achievement('Mine Games', 'achievementMine', (1, 1, 1.4),
+ 'Default:Rookie Onslaught', 10))
+ # 15
+ achs.append(
+ Achievement('Flawless Victory',
+ 'achievementFlawlessVictory', (1, 1, 1),
+ 'Default:Rookie Onslaught',
+ 15,
+ hard_mode_only=True))
+
+ # 10
+ achs.append(
+ Achievement('Rookie Football Victory',
+ 'achievementFootballVictory', (1.0, 1, 0.6),
+ 'Default:Rookie Football', 10))
+ # 10
+ achs.append(
+ Achievement('Super Punch', 'achievementSuperPunch', (1, 1, 1.8),
+ 'Default:Rookie Football', 10))
+ # 15
+ achs.append(
+ Achievement('Rookie Football Shutout',
+ 'achievementFootballShutout', (1, 1, 1),
+ 'Default:Rookie Football',
+ 15,
+ hard_mode_only=True))
+
+ # 15
+ achs.append(
+ Achievement('Pro Onslaught Victory', 'achievementOnslaught',
+ (0.3, 1, 2.0), 'Default:Pro Onslaught', 15))
+ # 15
+ achs.append(
+ Achievement('Boom Goes the Dynamite', 'achievementTNT',
+ (1.4, 1.2, 0.8), 'Default:Pro Onslaught', 15))
+ # 20
+ achs.append(
+ Achievement('Pro Boxer',
+ 'achievementBoxer', (2, 2, 0),
+ 'Default:Pro Onslaught',
+ 20,
+ hard_mode_only=True))
+
+ # 15
+ achs.append(
+ Achievement('Pro Football Victory', 'achievementFootballVictory',
+ (1.3, 1.3, 2.0), 'Default:Pro Football', 15))
+ # 15
+ achs.append(
+ Achievement('Super Mega Punch', 'achievementSuperPunch',
+ (2, 1, 0.6), 'Default:Pro Football', 15))
+ # 20
+ achs.append(
+ Achievement('Pro Football Shutout',
+ 'achievementFootballShutout', (0.7, 0.7, 2.0),
+ 'Default:Pro Football',
+ 20,
+ hard_mode_only=True))
+
+ # 15
+ achs.append(
+ Achievement('Pro Runaround Victory', 'achievementRunaround',
+ (1, 1, 1), 'Default:Pro Runaround', 15))
+ # 20
+ achs.append(
+ Achievement('Precision Bombing',
+ 'achievementCrossHair', (1, 1, 1.3),
+ 'Default:Pro Runaround',
+ 20,
+ hard_mode_only=True))
+ # 25
+ achs.append(
+ Achievement('The Wall',
+ 'achievementWall', (1, 0.7, 0.7),
+ 'Default:Pro Runaround',
+ 25,
+ hard_mode_only=True))
+
+ # 30
+ achs.append(
+ Achievement('Uber Onslaught Victory', 'achievementOnslaught',
+ (2, 2, 1), 'Default:Uber Onslaught', 30))
+ # 30
+ achs.append(
+ Achievement('Gold Miner',
+ 'achievementMine', (2, 1.6, 0.2),
+ 'Default:Uber Onslaught',
+ 30,
+ hard_mode_only=True))
+ # 30
+ achs.append(
+ Achievement('TNT Terror',
+ 'achievementTNT', (2, 1.8, 0.3),
+ 'Default:Uber Onslaught',
+ 30,
+ hard_mode_only=True))
+
+ # 30
+ achs.append(
+ Achievement('Uber Football Victory', 'achievementFootballVictory',
+ (1.8, 1.4, 0.3), 'Default:Uber Football', 30))
+ # 30
+ achs.append(
+ Achievement('Got the Moves',
+ 'achievementGotTheMoves', (2, 1, 0),
+ 'Default:Uber Football',
+ 30,
+ hard_mode_only=True))
+ # 40
+ achs.append(
+ Achievement('Uber Football Shutout',
+ 'achievementFootballShutout', (2, 2, 0),
+ 'Default:Uber Football',
+ 40,
+ hard_mode_only=True))
+
+ # 30
+ achs.append(
+ Achievement('Uber Runaround Victory', 'achievementRunaround',
+ (1.5, 1.2, 0.2), 'Default:Uber Runaround', 30))
+ # 40
+ achs.append(
+ Achievement('The Great Wall',
+ 'achievementWall', (2, 1.7, 0.4),
+ 'Default:Uber Runaround',
+ 40,
+ hard_mode_only=True))
+ # 40
+ achs.append(
+ Achievement('Stayin\' Alive',
+ 'achievementStayinAlive', (2, 2, 1),
+ 'Default:Uber Runaround',
+ 40,
+ hard_mode_only=True))
+
+ # 20
+ achs.append(
+ Achievement('Last Stand Master',
+ 'achievementMedalSmall', (2, 1.5, 0.3),
+ 'Default:The Last Stand',
+ 20,
+ hard_mode_only=True))
+ # 40
+ achs.append(
+ Achievement('Last Stand Wizard',
+ 'achievementMedalMedium', (2, 1.5, 0.3),
+ 'Default:The Last Stand',
+ 40,
+ hard_mode_only=True))
+ # 60
+ achs.append(
+ Achievement('Last Stand God',
+ 'achievementMedalLarge', (2, 1.5, 0.3),
+ 'Default:The Last Stand',
+ 60,
+ hard_mode_only=True))
+
+ # 5
+ achs.append(
+ Achievement('Onslaught Master', 'achievementMedalSmall',
+ (0.7, 1, 0.7), 'Challenges:Infinite Onslaught', 5))
+ # 15
+ achs.append(
+ Achievement('Onslaught Wizard', 'achievementMedalMedium',
+ (0.7, 1.0, 0.7), 'Challenges:Infinite Onslaught', 15))
+ # 30
+ achs.append(
+ Achievement('Onslaught God', 'achievementMedalLarge',
+ (0.7, 1.0, 0.7), 'Challenges:Infinite Onslaught', 30))
+
+ # 5
+ achs.append(
+ Achievement('Runaround Master', 'achievementMedalSmall',
+ (1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 5))
+ # 15
+ achs.append(
+ Achievement('Runaround Wizard', 'achievementMedalMedium',
+ (1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 15))
+ # 30
+ achs.append(
+ Achievement('Runaround God', 'achievementMedalLarge',
+ (1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 30))
+
+ def award_local_achievement(self, achname: str) -> None:
+ """For non-game-based achievements such as controller-connection."""
+ try:
+ ach = self.get_achievement(achname)
+ if not ach.complete:
+
+ # Report new achievements to the game-service.
+ _ba.report_achievement(achname)
+
+ # And to our account.
+ _ba.add_transaction({'type': 'ACHIEVEMENT', 'name': achname})
+
+ # Now attempt to show a banner.
+ self.display_achievement_banner(achname)
+
+ except Exception:
+ print_exception()
+
+ def display_achievement_banner(self, achname: str) -> None:
+ """Display a completion banner for an achievement.
+
+ (internal)
+
+ Used for server-driven achievements.
+ """
+ try:
+ # FIXME: Need to get these using the UI context or some other
+ # purely local context somehow instead of trying to inject these
+ # into whatever activity happens to be active
+ # (since that won't work while in client mode).
+ activity = _ba.get_foreground_host_activity()
+ if activity is not None:
+ with _ba.Context(activity):
+ self.get_achievement(achname).announce_completion()
+ except Exception:
+ print_exception('error showing server ach')
+
+ def set_completed_achievements(self, achs: Sequence[str]) -> None:
+ """Set the current state of completed achievements.
+
+ (internal)
+
+ All achievements not included here will be set incomplete.
+ """
+
+ # Note: This gets called whenever game-center/game-circle/etc tells
+ # us which achievements we currently have. We always defer to them,
+ # even if that means we have to un-set an achievement we think we have.
+
+ cfg = _ba.app.config
+ cfg['Achievements'] = {}
+ for a_name in achs:
+ self.get_achievement(a_name).set_complete(True)
+ cfg.commit()
+
+ def get_achievement(self, name: str) -> Achievement:
+ """Return an Achievement by name."""
+ achs = [a for a in self.achievements if a.name == name]
+ assert len(achs) < 2
+ if not achs:
+ raise ValueError("Invalid achievement name: '" + name + "'")
+ return achs[0]
+
+ def achievements_for_coop_level(self,
+ level_name: str) -> List[Achievement]:
+ """Given a level name, return achievements available for it."""
+
+ # For the Easy campaign we return achievements for the Default
+ # campaign too. (want the user to see what achievements are part of the
+ # level even if they can't unlock them all on easy mode).
+ return [
+ a for a in self.achievements
+ if a.level_name in (level_name,
+ level_name.replace('Easy', 'Default'))
+ ]
+
+ def _test(self) -> None:
+ """For testing achievement animations."""
+ from ba._enums import TimeType
+
+ def testcall1() -> None:
+ self.achievements[0].announce_completion()
+ self.achievements[1].announce_completion()
+ self.achievements[2].announce_completion()
+
+ def testcall2() -> None:
+ self.achievements[3].announce_completion()
+ self.achievements[4].announce_completion()
+ self.achievements[5].announce_completion()
+
+ _ba.timer(3.0, testcall1, timetype=TimeType.BASE)
+ _ba.timer(7.0, testcall2, timetype=TimeType.BASE)
def _get_ach_mult(include_pro_bonus: bool = False) -> int:
@@ -149,42 +409,28 @@ def _get_ach_mult(include_pro_bonus: bool = False) -> int:
(just for display; changing this here won't affect actual rewards)
"""
- from ba import _account
val: int = _ba.get_account_misc_read_val('achAwardMult', 5)
assert isinstance(val, int)
- if include_pro_bonus and _account.have_pro():
+ if include_pro_bonus and _ba.app.accounts.have_pro():
val *= 2
return val
-def get_achievements_for_coop_level(level_name: str) -> List[Achievement]:
- """Given a level name, return achievements available for it."""
-
- # For the Easy campaign we return achievements for the Default
- # campaign too. (want the user to see what achievements are part of the
- # level even if they can't unlock them all on easy mode).
- return [
- a for a in _ba.app.achievements
- if a.level_name in (level_name, level_name.replace('Easy', 'Default'))
- ]
-
-
def _display_next_achievement() -> None:
# Pull the first achievement off the list and display it, or kill the
# display-timer if the list is empty.
app = _ba.app
- if app.achievements_to_display:
+ if app.ach.achievements_to_display:
try:
- ach, sound = app.achievements_to_display.pop(0)
+ ach, sound = app.ach.achievements_to_display.pop(0)
ach.show_completion_banner(sound)
except Exception:
- from ba import _error
- _error.print_exception('error showing next achievement')
- app.achievements_to_display = []
- app.achievement_display_timer = None
+ print_exception('error showing next achievement')
+ app.ach.achievements_to_display = []
+ app.ach.achievement_display_timer = None
else:
- app.achievement_display_timer = None
+ app.ach.achievement_display_timer = None
class Achievement:
@@ -254,18 +500,18 @@ class Achievement:
return
# If we're being freshly complete, display/report it and whatnot.
- if (self, sound) not in app.achievements_to_display:
- app.achievements_to_display.append((self, sound))
+ if (self, sound) not in app.ach.achievements_to_display:
+ app.ach.achievements_to_display.append((self, sound))
# If there's no achievement display timer going, kick one off
# (if one's already running it will pick this up before it dies).
# Need to check last time too; its possible our timer wasn't able to
# clear itself if an activity died and took it down with it.
- if ((app.achievement_display_timer is None or
- _ba.time(TimeType.REAL) - app.last_achievement_display_time > 2.0)
- and _ba.getactivity(doraise=False) is not None):
- app.achievement_display_timer = _ba.Timer(
+ if ((app.ach.achievement_display_timer is None
+ or _ba.time(TimeType.REAL) - app.ach.last_achievement_display_time
+ > 2.0) and _ba.getactivity(doraise=False) is not None):
+ app.ach.achievement_display_timer = _ba.Timer(
1.0,
_display_next_achievement,
repeat=True,
@@ -287,36 +533,37 @@ class Achievement:
@property
def display_name(self) -> ba.Lstr:
"""Return a ba.Lstr for this Achievement's name."""
- from ba._lang import Lstr
+ from ba._language import Lstr
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 = ''
except Exception:
- from ba import _error
name = ''
- _error.print_exception()
+ print_exception()
return Lstr(resource='achievements.' + self._name + '.name',
subs=[('${LEVEL}', name)])
@property
def description(self) -> ba.Lstr:
"""Get a ba.Lstr for the Achievement's brief description."""
- from ba._lang import Lstr, get_resource
- if 'description' in get_resource('achievements')[self._name]:
+ from ba._language import Lstr
+ if 'description' in _ba.app.lang.get_resource('achievements')[
+ self._name]:
return Lstr(resource='achievements.' + self._name + '.description')
return Lstr(resource='achievements.' + self._name + '.descriptionFull')
@property
def description_complete(self) -> ba.Lstr:
"""Get a ba.Lstr for the Achievement's description when completed."""
- from ba._lang import Lstr, get_resource
- if 'descriptionComplete' in get_resource('achievements')[self._name]:
+ from ba._language import Lstr
+ if 'descriptionComplete' in _ba.app.lang.get_resource('achievements')[
+ self._name]:
return Lstr(resource='achievements.' + self._name +
'.descriptionComplete')
return Lstr(resource='achievements.' + self._name +
@@ -325,7 +572,7 @@ class Achievement:
@property
def description_full(self) -> ba.Lstr:
"""Get a ba.Lstr for the Achievement's full description."""
- from ba._lang import Lstr
+ from ba._language import Lstr
return Lstr(
resource='achievements.' + self._name + '.descriptionFull',
@@ -336,7 +583,7 @@ class Achievement:
@property
def description_full_complete(self) -> ba.Lstr:
"""Get a ba.Lstr for the Achievement's full desc. when completed."""
- from ba._lang import Lstr
+ from ba._language import Lstr
return Lstr(
resource='achievements.' + self._name + '.descriptionFullComplete',
subs=[('${LEVEL}',
@@ -371,8 +618,9 @@ class Achievement:
Shows the Achievement icon, name, and description.
"""
# pylint: disable=cyclic-import
- from ba._lang import Lstr
+ from ba._language import Lstr
from ba._enums import SpecialChar
+ from ba._coopsession import CoopSession
from bastd.actor.image import Image
from bastd.actor.text import Text
@@ -396,7 +644,7 @@ class Achievement:
v_attach = Text.VAttach.TOP
attach = Image.Attach.TOP_CENTER
else:
- raise Exception('invalid style "' + style + '"')
+ raise ValueError('invalid style "' + style + '"')
# Attempt to determine what campaign we're in
# (so we know whether to show "hard mode only").
@@ -404,12 +652,15 @@ 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')
+ print_exception('Error determining campaign.')
hmo = False
objs: List[ba.Actor]
@@ -659,7 +910,7 @@ class Achievement:
def _remove_banner_slot(self) -> None:
assert self._completion_banner_slot is not None
- _ba.app.achievement_completion_banner_slots.remove(
+ _ba.app.ach.achievement_completion_banner_slots.remove(
self._completion_banner_slot)
self._completion_banner_slot = None
@@ -670,15 +921,15 @@ class Achievement:
from bastd.actor.text import Text
from bastd.actor.image import Image
from ba._general import WeakCall
- from ba._lang import Lstr
+ from ba._language import Lstr
from ba._messages import DieMessage
from ba._enums import TimeType, SpecialChar
app = _ba.app
- app.last_achievement_display_time = _ba.time(TimeType.REAL)
+ app.ach.last_achievement_display_time = _ba.time(TimeType.REAL)
# 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
@@ -705,8 +956,8 @@ class Achievement:
# Find the first free slot.
i = 0
while True:
- if i not in app.achievement_completion_banner_slots:
- app.achievement_completion_banner_slots.add(i)
+ if i not in app.ach.achievement_completion_banner_slots:
+ app.ach.achievement_completion_banner_slots.add(i)
self._completion_banner_slot = i
# Remove us from that slot when we close.
@@ -926,7 +1177,7 @@ class Achievement:
objt.node.host_only = True
# Add the 'x 2' if we've got pro.
- if _account.have_pro():
+ if app.accounts.have_pro():
objt = Text('x 2',
position=(-120 - 180 + 45, 80 + y_offs - 50),
v_attach=Text.VAttach.BOTTOM,
@@ -964,252 +1215,3 @@ class Achievement:
for actor in objs:
_ba.timer(out_time + 1.000,
WeakCall(actor.handlemessage, DieMessage()))
-
-
-def init_achievements() -> None:
- """Fill in available achievements."""
-
- achs = _ba.app.achievements
-
- # 5
- achs.append(
- Achievement('In Control', 'achievementInControl', (1, 1, 1), '', 5))
- # 15
- achs.append(
- Achievement('Sharing is Caring', 'achievementSharingIsCaring',
- (1, 1, 1), '', 15))
- # 10
- achs.append(
- Achievement('Dual Wielding', 'achievementDualWielding', (1, 1, 1), '',
- 10))
-
- # 10
- achs.append(
- Achievement('Free Loader', 'achievementFreeLoader', (1, 1, 1), '', 10))
- # 20
- achs.append(
- Achievement('Team Player', 'achievementTeamPlayer', (1, 1, 1), '', 20))
-
- # 5
- achs.append(
- Achievement('Onslaught Training Victory', 'achievementOnslaught',
- (1, 1, 1), 'Default:Onslaught Training', 5))
- # 5
- achs.append(
- Achievement('Off You Go Then', 'achievementOffYouGo', (1, 1.1, 1.3),
- 'Default:Onslaught Training', 5))
- # 10
- achs.append(
- Achievement('Boxer',
- 'achievementBoxer', (1, 0.6, 0.6),
- 'Default:Onslaught Training',
- 10,
- hard_mode_only=True))
-
- # 10
- achs.append(
- Achievement('Rookie Onslaught Victory', 'achievementOnslaught',
- (0.5, 1.4, 0.6), 'Default:Rookie Onslaught', 10))
- # 10
- achs.append(
- Achievement('Mine Games', 'achievementMine', (1, 1, 1.4),
- 'Default:Rookie Onslaught', 10))
- # 15
- achs.append(
- Achievement('Flawless Victory',
- 'achievementFlawlessVictory', (1, 1, 1),
- 'Default:Rookie Onslaught',
- 15,
- hard_mode_only=True))
-
- # 10
- achs.append(
- Achievement('Rookie Football Victory', 'achievementFootballVictory',
- (1.0, 1, 0.6), 'Default:Rookie Football', 10))
- # 10
- achs.append(
- Achievement('Super Punch', 'achievementSuperPunch', (1, 1, 1.8),
- 'Default:Rookie Football', 10))
- # 15
- achs.append(
- Achievement('Rookie Football Shutout',
- 'achievementFootballShutout', (1, 1, 1),
- 'Default:Rookie Football',
- 15,
- hard_mode_only=True))
-
- # 15
- achs.append(
- Achievement('Pro Onslaught Victory', 'achievementOnslaught',
- (0.3, 1, 2.0), 'Default:Pro Onslaught', 15))
- # 15
- achs.append(
- Achievement('Boom Goes the Dynamite', 'achievementTNT',
- (1.4, 1.2, 0.8), 'Default:Pro Onslaught', 15))
- # 20
- achs.append(
- Achievement('Pro Boxer',
- 'achievementBoxer', (2, 2, 0),
- 'Default:Pro Onslaught',
- 20,
- hard_mode_only=True))
-
- # 15
- achs.append(
- Achievement('Pro Football Victory', 'achievementFootballVictory',
- (1.3, 1.3, 2.0), 'Default:Pro Football', 15))
- # 15
- achs.append(
- Achievement('Super Mega Punch', 'achievementSuperPunch', (2, 1, 0.6),
- 'Default:Pro Football', 15))
- # 20
- achs.append(
- Achievement('Pro Football Shutout',
- 'achievementFootballShutout', (0.7, 0.7, 2.0),
- 'Default:Pro Football',
- 20,
- hard_mode_only=True))
-
- # 15
- achs.append(
- Achievement('Pro Runaround Victory', 'achievementRunaround', (1, 1, 1),
- 'Default:Pro Runaround', 15))
- # 20
- achs.append(
- Achievement('Precision Bombing',
- 'achievementCrossHair', (1, 1, 1.3),
- 'Default:Pro Runaround',
- 20,
- hard_mode_only=True))
- # 25
- achs.append(
- Achievement('The Wall',
- 'achievementWall', (1, 0.7, 0.7),
- 'Default:Pro Runaround',
- 25,
- hard_mode_only=True))
-
- # 30
- achs.append(
- Achievement('Uber Onslaught Victory', 'achievementOnslaught',
- (2, 2, 1), 'Default:Uber Onslaught', 30))
- # 30
- achs.append(
- Achievement('Gold Miner',
- 'achievementMine', (2, 1.6, 0.2),
- 'Default:Uber Onslaught',
- 30,
- hard_mode_only=True))
- # 30
- achs.append(
- Achievement('TNT Terror',
- 'achievementTNT', (2, 1.8, 0.3),
- 'Default:Uber Onslaught',
- 30,
- hard_mode_only=True))
-
- # 30
- achs.append(
- Achievement('Uber Football Victory', 'achievementFootballVictory',
- (1.8, 1.4, 0.3), 'Default:Uber Football', 30))
- # 30
- achs.append(
- Achievement('Got the Moves',
- 'achievementGotTheMoves', (2, 1, 0),
- 'Default:Uber Football',
- 30,
- hard_mode_only=True))
- # 40
- achs.append(
- Achievement('Uber Football Shutout',
- 'achievementFootballShutout', (2, 2, 0),
- 'Default:Uber Football',
- 40,
- hard_mode_only=True))
-
- # 30
- achs.append(
- Achievement('Uber Runaround Victory', 'achievementRunaround',
- (1.5, 1.2, 0.2), 'Default:Uber Runaround', 30))
- # 40
- achs.append(
- Achievement('The Great Wall',
- 'achievementWall', (2, 1.7, 0.4),
- 'Default:Uber Runaround',
- 40,
- hard_mode_only=True))
- # 40
- achs.append(
- Achievement('Stayin\' Alive',
- 'achievementStayinAlive', (2, 2, 1),
- 'Default:Uber Runaround',
- 40,
- hard_mode_only=True))
-
- # 20
- achs.append(
- Achievement('Last Stand Master',
- 'achievementMedalSmall', (2, 1.5, 0.3),
- 'Default:The Last Stand',
- 20,
- hard_mode_only=True))
- # 40
- achs.append(
- Achievement('Last Stand Wizard',
- 'achievementMedalMedium', (2, 1.5, 0.3),
- 'Default:The Last Stand',
- 40,
- hard_mode_only=True))
- # 60
- achs.append(
- Achievement('Last Stand God',
- 'achievementMedalLarge', (2, 1.5, 0.3),
- 'Default:The Last Stand',
- 60,
- hard_mode_only=True))
-
- # 5
- achs.append(
- Achievement('Onslaught Master', 'achievementMedalSmall', (0.7, 1, 0.7),
- 'Challenges:Infinite Onslaught', 5))
- # 15
- achs.append(
- Achievement('Onslaught Wizard', 'achievementMedalMedium',
- (0.7, 1.0, 0.7), 'Challenges:Infinite Onslaught', 15))
- # 30
- achs.append(
- Achievement('Onslaught God', 'achievementMedalLarge', (0.7, 1.0, 0.7),
- 'Challenges:Infinite Onslaught', 30))
-
- # 5
- achs.append(
- Achievement('Runaround Master', 'achievementMedalSmall',
- (1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 5))
- # 15
- achs.append(
- Achievement('Runaround Wizard', 'achievementMedalMedium',
- (1.0, 1.0, 1.2), 'Challenges:Infinite Runaround', 15))
- # 30
- achs.append(
- Achievement('Runaround God', 'achievementMedalLarge', (1.0, 1.0, 1.2),
- 'Challenges:Infinite Runaround', 30))
-
-
-def _test() -> None:
- """For testing achievement animations."""
- from ba._enums import TimeType
-
- def testcall1() -> None:
- app = _ba.app
- app.achievements[0].announce_completion()
- app.achievements[1].announce_completion()
- app.achievements[2].announce_completion()
-
- def testcall2() -> None:
- app = _ba.app
- app.achievements[3].announce_completion()
- app.achievements[4].announce_completion()
- app.achievements[5].announce_completion()
-
- _ba.timer(3.0, testcall1, timetype=TimeType.BASE)
- _ba.timer(7.0, testcall2, timetype=TimeType.BASE)
diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py
index 97294640..2304ca94 100644
--- a/assets/src/ba_data/python/ba/_activity.py
+++ b/assets/src/ba_data/python/ba/_activity.py
@@ -1,31 +1,19 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
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, SessionTeamNotFoundError,
+ SessionPlayerNotFoundError, NodeNotFoundError)
from ba._dependency import DependencyComponent
+from ba._general import Call, verify_object_death
+from ba._messages import UNHANDLED
if TYPE_CHECKING:
from weakref import ReferenceType
@@ -33,8 +21,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
@@ -45,8 +36,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
@@ -63,15 +57,75 @@ class Activity(DependencyComponent):
# pylint: disable=too-many-public-methods
- # Annotating attr types at the class level lets us introspect them.
- settings: Dict[str, Any]
- teams: List[ba.Team]
- players: List[ba.Player]
+ # Annotating attr types at the class level lets us introspect at runtime.
+ settings_raw: Dict[str, Any]
+ teams: List[TeamType]
+ players: List[PlayerType]
- def __init__(self, settings: Dict[str, Any]):
- """Creates an activity in the current ba.Session.
+ # 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
- The activity will not be actually run until ba.Session.set_activity()
+ # 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_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
+ # 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):
+ """Creates an Activity in the current ba.Session.
+
+ 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.
@@ -81,107 +135,42 @@ class Activity(DependencyComponent):
"""
super().__init__()
- # FIXME: Relocate 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')
- self._session = weakref.ref(session)
+ 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]
+ self._teamtype: Type[TeamType]
+ self._setup_player_and_team_types()
+
+ # FIXME: Relocate or remove the need for this stuff.
+ self.paused_text: Optional[ba.Actor] = None
+
+ self._session = weakref.ref(_ba.getsession())
# Preloaded data for actors, maps, etc; indexed by type.
self.preloads: Dict[Type, Any] = {}
- if not isinstance(settings, dict):
- raise Exception('expected dict for settings')
- if _ba.getactivity(doraise=False) is not self:
- raise Exception('invalid context state')
-
- self.settings = settings
+ # 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
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._called_activity_on_transition_in = False
- self._called_activity_on_begin = False
-
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,
- # change music, or anything else with global implications once this
- # happens.
+ 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]] = []
self._transitioning_out = False
# A handy place to put most actors; this list is pruned of dead
@@ -189,15 +178,41 @@ 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._stats: Optional[ba.Stats] = None
self.lobby = None
- self._prune_dead_objects_timer: Optional[ba.Timer] = None
+ self._stats: Optional[ba.Stats] = None
+ self._customdata: Optional[dict] = {}
+
+ def __del__(self) -> None:
+
+ # 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.
+ if not self._expired:
+ with _ba.Context('empty'):
+ self._expire()
+
+ # Inform our owner that we officially kicked the bucket.
+ if self._transitioning_out:
+ session = self._session()
+ if session is not None:
+ _ba.pushcall(
+ 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:
@@ -220,8 +235,20 @@ class Activity(DependencyComponent):
can begin.
"""
- def is_expired(self) -> bool:
- """Return whether the activity is expired.
+ @property
+ 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._customdata, dict)
+ return self._customdata
+
+ @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,
@@ -229,62 +256,25 @@ class Activity(DependencyComponent):
"""
return self._expired
- def __del__(self) -> None:
+ @property
+ def playertype(self) -> Type[PlayerType]:
+ """The type of ba.Player this Activity is using."""
+ return self._playertype
- 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.
- if not self._expired:
- 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.
- 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)
+ @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
- def set_immediate_end(self, results: ba.TeamGameResults, delay: float,
- force: bool) -> None:
- """Set the activity to die immediately after beginning.
+ def expire(self) -> None:
+ """Begin the process of tearing down the activity.
(internal)
"""
- if self.has_begun():
- raise Exception('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 _get_player_icon(self, player: ba.Player) -> Dict[str, Any]:
-
- # 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:
- from ba._general import Call
from ba._enums import TimeType
# Create a real-timer that watches a weak-ref of this activity
@@ -308,7 +298,410 @@ 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}')
+
+ def retain_actor(self, actor: ba.Actor) -> None:
+ """Add a strong-reference to a ba.Actor to this Activity.
+
+ The reference will be lazily released once ba.Actor.exists()
+ returns False for the Actor. The ba.Actor.autoretain() method
+ is a convenient way to access this same functionality.
+ """
+ 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:
+ """Add a weak-reference to a ba.Actor to the ba.Activity.
+
+ (called by the ba.Actor base class)
+ """
+ if __debug__:
+ from ba._actor import Actor
+ assert isinstance(actor, Actor)
+ self._actor_weak_refs.append(weakref.ref(actor))
+
+ @property
+ def session(self) -> ba.Session:
+ """The ba.Session this ba.Activity belongs go.
+
+ Raises a ba.SessionNotFoundError if the Session no longer exists.
+ """
+ session = self._session()
+ if session is None:
+ from ba._error import SessionNotFoundError
+ raise SessionNotFoundError()
+ return session
+
+ 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: PlayerType) -> None:
+ """Called when a ba.Player is leaving the Activity."""
+
+ 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: 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 players
+ or teams, however. They remain owned by the previous Activity
+ up until ba.Activity.on_begin() is called.
+ """
+
+ def on_transition_out(self) -> None:
+ """Called when your activity begins transitioning out.
+
+ Note that this may happen at any time even if end() has not been
+ called.
+ """
+
+ def on_begin(self) -> None:
+ """Called once the previous ba.Activity has finished transitioning out.
+
+ At this point the activity's initial players and teams are filled in
+ and it should begin its actual game logic.
+ """
+
+ def handlemessage(self, msg: Any) -> Any:
+ """General message handling; can be passed any message object."""
+ del msg # Unused arg.
+ return UNHANDLED
+
+ def has_transitioned_in(self) -> bool:
+ """Return whether on_transition_in() has been called."""
+ return self._has_transitioned_in
+
+ def has_begun(self) -> bool:
+ """Return whether on_begin() has been called."""
+ return self._has_begun
+
+ def has_ended(self) -> bool:
+ """Return whether the activity has commenced ending."""
+ return self._has_ended
+
+ def is_transitioning_out(self) -> bool:
+ """Return whether on_transition_out() has been called."""
+ return self._transitioning_out
+
+ def transition_in(self, prev_globals: Optional[ba.Node]) -> None:
+ """Called by Session to kick off transition-in.
+
+ (internal)
+ """
+ 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.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:
+ 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_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
+ glb.vr_overlay_center_enabled = (
+ prev_globals.vr_overlay_center_enabled)
+
+ # 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 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()
+
+ try:
+ self.on_transition_in()
+ except Exception:
+ 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.
+ 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(f'Error in on_transition_out for {self}.')
+
+ def begin(self, session: ba.Session) -> None:
+ """Begin the activity.
+
+ (internal)
+ """
+
+ assert not self._has_begun
+
+ # Inherit stats from the session.
+ self._stats = session.stats
+
+ # Add session's teams in.
+ for team in session.sessionteams:
+ self.add_team(team)
+
+ # Add session's players in.
+ for player in session.sessionplayers:
+ self.add_player(player)
+
+ self._has_begun = True
+
+ # 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,
+ 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.
+
+ 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.sessionteam is not None
+ sessionplayer.resetinput()
+ sessionteam = sessionplayer.sessionteam
+ assert sessionplayer in sessionteam.players
+ team = sessionteam.activityteam
+ assert team is not None
+ sessionplayer.setactivity(self)
+ with _ba.Context(self):
+ sessionplayer.activityplayer = 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(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.
+
+ (internal)
+ """
+ assert not self.expired
+
+ player: Any = sessionplayer.activityplayer
+ assert isinstance(player, self._playertype)
+ team: Any = sessionplayer.sessionteam.activityteam
+ 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
+
+ # This should allow our ba.Player instance to die.
+ # Complain if that doesn't happen.
+ # verify_object_death(player)
+
+ with _ba.Context(self):
+ try:
+ self.on_player_leave(player)
+ except Exception:
+ 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}.')
+
+ 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:
+ """Add a team to the Activity
+
+ (internal)
+ """
+ assert not self.expired
+
+ with _ba.Context(self):
+ sessionteam.activityteam = 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:
+ """Remove a team from a Running Activity
+
+ (internal)
+ """
+ assert not self.expired
+ assert sessionteam.activityteam is not None
+
+ team: Any = sessionteam.activityteam
+ 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:
+ team.leave()
+ except Exception:
+ print_exception(f'Error on leave for {team} in {self}.')
+
+ 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
+ # 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.activityplayer = None
+
+ 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
+ # 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):
+ 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)
@classmethod
def _check_activity_death(cls, activity_ref: ReferenceType[Activity],
@@ -346,315 +739,132 @@ class Activity(DependencyComponent):
_ba.quit()
except Exception:
- from ba import _error
- _error.print_exception('exception on _check_activity_death:')
+ print_exception('Error 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}.')
- # 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()
+ self._customdata = None
except Exception:
- _error.print_exception(
- 'Exception during ba.Activity._expire() destroying data:')
+ print_exception(f'Error clearing customdata for {self}.')
- def _prune_dead_objects(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()
+ # Don't want to be holding any delay-delete refs at this point.
+ self._prune_delay_deletes()
- def retain_actor(self, actor: ba.Actor) -> None:
- """Add a strong-reference to a ba.Actor to this Activity.
+ self._expire_actors()
+ self._expire_players()
+ self._expire_teams()
- The reference will be lazily released once ba.Actor.exists()
- 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
- 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)')
- self._actor_refs.append(actor)
+ # 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(f'Error expiring _activity_data for {self}.')
- def add_actor_weak_ref(self, actor: ba.Actor) -> None:
- """Add a weak-reference to a ba.Actor to the ba.Activity.
-
- (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)')
- self._actor_weak_refs.append(weakref.ref(actor))
-
- @property
- def session(self) -> ba.Session:
- """The ba.Session this ba.Activity belongs go.
-
- Raises a ba.SessionNotFoundError if the Session no longer exists.
- """
- session = self._session()
- if session is None:
- from ba._error import SessionNotFoundError
- raise SessionNotFoundError()
- return session
-
- def on_player_join(self, player: ba.Player) -> 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:
- """Called when a ba.Player is leaving the Activity."""
-
- def on_team_join(self, team: ba.Team) -> 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:
- """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
- 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
- called.
- """
-
- def on_begin(self) -> None:
- """Called once the previous ba.Activity has finished transitioning out.
-
- 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."""
-
- 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
-
- def has_begun(self) -> bool:
- """Return whether on_begin() has been called."""
- return self._has_begun
-
- def has_ended(self) -> bool:
- """Return whether the activity has commenced ending."""
- return self._has_ended
-
- def is_transitioning_out(self) -> bool:
- """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.
-
- (internal)
- """
- 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
- 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:
+ def _expire_actors(self) -> None:
+ # Expire all Actors.
+ for actor_ref in self._actor_weak_refs:
+ actor = actor_ref()
+ if actor is not None:
+ verify_object_death(actor)
try:
- team: Optional[ba.Team] = player.team
- except _error.TeamNotFoundError:
- team = None
+ actor.on_expire()
+ except Exception:
+ print_exception(f'Error in Actor.on_expire()'
+ f' for {actor_ref()}.')
- 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)
- else:
- _error.print_error(
- 'got nonexistent player in Activity._begin()')
+ 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)
+
+ 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)
- # 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')
- self.teams.append(team)
try:
- with _ba.Context(self):
- self.on_team_join(team)
+ player.expire()
except Exception:
- _error.print_exception('Error in on_team_join for', self)
+ print_exception(f'Error expiring {player}')
- # 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)
+ # Reset the SessionPlayer to a not-in-an-activity state.
try:
- with _ba.Context(self):
- self.on_player_join(player)
+ 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:
- _error.print_exception('Error in on_player_join for', self)
+ print_exception(f'Error expiring {player}.')
- with _ba.Context(self):
- # And finally tell the game to start.
- self._has_begun = True
- self.on_begin()
+ def _expire_teams(self) -> None:
- # Make sure that ba.Activity.on_transition_in() got called
- # at some point.
- if not self._called_activity_on_transition_in:
- _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?')
+ # 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)
- # Make sure that ba.Activity.on_begin() got called at some point.
- if not self._called_activity_on_begin:
- _error.print_error(
- 'ba.Activity.on_begin() never got called for ' + str(self) +
- '; did you forget to call it in your on_begin override?')
+ for team in self.teams:
+ # This should allow our ba.Team instance to die.
+ # Complain if that doesn't happen.
+ verify_object_death(team)
- # If the whole session wants to die and was waiting on us, can get
- # that going 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)
+ try:
+ team.expire()
+ except Exception:
+ print_exception(f'Error expiring {team}')
+
+ try:
+ sessionteam = team.sessionteam
+ sessionteam.activityteam = None
+ 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 has left the game)
+ pass
+ except Exception:
+ print_exception(f'Error expiring Team {team}.')
+
+ 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()
+
+ # 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/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py
index 9e53b6a6..c51655db 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
@@ -26,6 +8,10 @@ from typing import TYPE_CHECKING
import _ba
from ba._activity import Activity
from ba._music import setmusic, MusicType
+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
if TYPE_CHECKING:
from typing import Any, Dict, Optional
@@ -33,17 +19,17 @@ if TYPE_CHECKING:
from ba._lobby import JoinInfo
-class EndSessionActivity(Activity):
+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.
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:
@@ -54,20 +40,19 @@ class EndSessionActivity(Activity):
def on_begin(self) -> None:
# pylint: disable=cyclic-import
from bastd.mainmenu import MainMenuSession
- from ba._apputils import call_after_ad
from ba._general import Call
super().on_begin()
_ba.unlock_all_input()
- call_after_ad(Call(_ba.new_host_session, MainMenuSession))
+ _ba.app.ads.call_after_ad(Call(_ba.new_host_session, MainMenuSession))
-class JoinActivity(Activity):
+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.
@@ -98,22 +83,22 @@ class JoinActivity(Activity):
_ba.set_analytics_screen('Joining Screen')
-class TransitionActivity(Activity):
- """A simple overlay fade out/in.
+class TransitionActivity(Activity[EmptyPlayer, EmptyTeam]):
+ """A simple overlay to fade out/in.
Useful as a bare minimum transition between two level based activities.
"""
- def __init__(self, settings: Dict[str, Any]):
- super().__init__(settings)
+ # 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
- # 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_camera_vr_offset = True # Don't change.
- self.inherits_vr_overlay_center = True
- self.use_fixed_vr_overlay = True
+ def __init__(self, settings: dict):
+ super().__init__(settings)
self._background: Optional[ba.Actor] = None
def on_transition_in(self) -> None:
@@ -131,19 +116,21 @@ class TransitionActivity(Activity):
_ba.timer(0.1, self.end)
-class ScoreScreenActivity(Activity):
+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]):
+ 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_camera_vr_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
@@ -155,16 +142,15 @@ class ScoreScreenActivity(Activity):
self._custom_continue_message: Optional[ba.Lstr] = None
self._server_transitioning: Optional[bool] = None
- def on_player_join(self, player: ba.Player) -> None:
- from ba import _general
+ def on_player_join(self, player: EmptyPlayer) -> None:
+ 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
@@ -180,18 +166,18 @@ class ScoreScreenActivity(Activity):
def on_begin(self) -> None:
# pylint: disable=cyclic-import
from bastd.actor.text import Text
- from ba import _lang
+ from ba import _language
super().on_begin()
# 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.ui.uiscale is UIScale.LARGE:
# FIXME: Need a better way to determine whether we've probably
# got a keyboard.
- sval = _lang.Lstr(resource='pressAnyKeyButtonText')
+ sval = _language.Lstr(resource='pressAnyKeyButtonText')
else:
- sval = _lang.Lstr(resource='pressAnyButtonText')
+ sval = _language.Lstr(resource='pressAnyButtonText')
Text(self._custom_continue_message
if self._custom_continue_message is not None else sval,
@@ -221,11 +207,11 @@ class ScoreScreenActivity(Activity):
# Otherwise end the activity normally.
self.end()
- def _safe_assign(self, player: ba.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).
+ # (though theoretically that should be ok).
if not self.is_transitioning_out() and player:
- player.assign_input_call(
- ('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/_actor.py b/assets/src/ba_data/python/ba/_actor.py
index d45ea744..5c8f7aaf 100644
--- a/assets/src/ba_data/python/ba/_actor.py
+++ b/assets/src/ba_data/python/ba/_actor.py
@@ -1,37 +1,18 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
import weakref
-from typing import TYPE_CHECKING, TypeVar
+from typing import TYPE_CHECKING, TypeVar, overload
-from ba._messages import DieMessage, DeathType, OutOfBoundsMessage
-from ba import _error
+from ba._messages import DieMessage, DeathType, OutOfBoundsMessage, UNHANDLED
+from ba._error import print_exception, ActivityNotFoundError
import _ba
if TYPE_CHECKING:
- from typing import Any, Optional
-
+ from typing import Any, Optional, Literal
import ba
T = TypeVar('T', bound='Actor')
@@ -45,7 +26,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
@@ -94,24 +76,23 @@ 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.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."""
- if __debug__:
- self._handlemessage_sanity_check()
+ assert not self.expired
# By default, actors going out-of-bounds simply kill themselves.
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,16 +107,16 @@ class Actor:
"""
activity = self._activity()
if activity is None:
- raise _error.ActivityNotFoundError()
+ raise ActivityNotFoundError()
activity.retain_actor(self)
return self
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
@@ -144,13 +125,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.
@@ -169,7 +151,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:
@@ -186,23 +167,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__:
- _error.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}')
-
@property
def activity(self) -> ba.Activity:
"""The Activity this Actor was created in.
@@ -211,16 +175,26 @@ class Actor:
"""
activity = self._activity()
if activity is None:
- raise _error.ActivityNotFoundError()
+ 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.
If the Activity no longer exists, raises a ba.ActivityNotFoundError
- or returns None depending on whether 'doraise' is set.
+ or returns None depending on whether 'doraise' is True.
"""
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/_ads.py b/assets/src/ba_data/python/ba/_ads.py
new file mode 100644
index 00000000..74939794
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_ads.py
@@ -0,0 +1,186 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Functionality related to ads."""
+from __future__ import annotations
+
+import time
+from typing import TYPE_CHECKING
+
+import _ba
+
+if TYPE_CHECKING:
+ from typing import Optional, Callable, Any
+
+
+class AdsSubsystem:
+ """Subsystem for ads functionality in the app.
+
+ Category: App Classes
+
+ Access the single shared instance of this class at 'ba.app.ads'.
+ """
+
+ def __init__(self) -> None:
+ self.last_ad_network = 'unknown'
+ self.last_ad_network_set_time = time.time()
+ self.ad_amt: Optional[float] = None
+ self.last_ad_purpose = 'invalid'
+ self.attempted_first_ad = False
+ self.last_in_game_ad_remove_message_show_time: Optional[float] = None
+ self.last_ad_completion_time: Optional[float] = None
+ self.last_ad_was_short = False
+
+ def do_remove_in_game_ads_message(self) -> None:
+ """(internal)"""
+ from ba._language import Lstr
+ from ba._enums import TimeType
+
+ # Print this message once every 10 minutes at most.
+ tval = _ba.time(TimeType.REAL)
+ if (self.last_in_game_ad_remove_message_show_time is None or
+ (tval - self.last_in_game_ad_remove_message_show_time > 60 * 10)):
+ self.last_in_game_ad_remove_message_show_time = tval
+ with _ba.Context('ui'):
+ _ba.timer(
+ 1.0,
+ lambda: _ba.screenmessage(Lstr(
+ resource='removeInGameAdsText',
+ subs=[('${PRO}',
+ Lstr(resource='store.bombSquadProNameText')),
+ ('${APP_NAME}', Lstr(resource='titleText'))]),
+ color=(1, 1, 0)),
+ timetype=TimeType.REAL)
+
+ def show_ad(self,
+ purpose: str,
+ on_completion_call: Callable[[], Any] = None) -> None:
+ """(internal)"""
+ self.last_ad_purpose = purpose
+ _ba.show_ad(purpose, on_completion_call)
+
+ def show_ad_2(self,
+ purpose: str,
+ on_completion_call: Callable[[bool], Any] = None) -> None:
+ """(internal)"""
+ self.last_ad_purpose = purpose
+ _ba.show_ad_2(purpose, on_completion_call)
+
+ def call_after_ad(self, call: Callable[[], Any]) -> None:
+ """Run a call after potentially showing an ad."""
+ # pylint: disable=too-many-statements
+ # pylint: disable=too-many-branches
+ # pylint: disable=too-many-locals
+ from ba._enums import TimeType
+ app = _ba.app
+ show = True
+
+ # No ads without net-connections, etc.
+ if not _ba.can_show_ad():
+ show = False
+ if app.accounts.have_pro():
+ show = False # Pro disables interstitials.
+ try:
+ session = _ba.get_foreground_host_session()
+ assert session is not None
+ is_tournament = session.tournament_id is not None
+ except Exception:
+ is_tournament = False
+ if is_tournament:
+ show = False # Never show ads during tournaments.
+
+ if show:
+ interval: Optional[float]
+ launch_count = app.config.get('launchCount', 0)
+
+ # If we're seeing short ads we may want to space them differently.
+ interval_mult = (_ba.get_account_misc_read_val(
+ 'ads.shortIntervalMult', 1.0)
+ if self.last_ad_was_short else 1.0)
+ if self.ad_amt is None:
+ if launch_count <= 1:
+ self.ad_amt = _ba.get_account_misc_read_val(
+ 'ads.startVal1', 0.99)
+ else:
+ self.ad_amt = _ba.get_account_misc_read_val(
+ 'ads.startVal2', 1.0)
+ interval = None
+ else:
+ # So far we're cleared to show; now calc our
+ # ad-show-threshold and see if we should *actually* show
+ # (we reach our threshold faster the longer we've been
+ # playing).
+ base = 'ads' if _ba.has_video_ads() else 'ads2'
+ min_lc = _ba.get_account_misc_read_val(base + '.minLC', 0.0)
+ max_lc = _ba.get_account_misc_read_val(base + '.maxLC', 5.0)
+ min_lc_scale = (_ba.get_account_misc_read_val(
+ base + '.minLCScale', 0.25))
+ max_lc_scale = (_ba.get_account_misc_read_val(
+ base + '.maxLCScale', 0.34))
+ min_lc_interval = (_ba.get_account_misc_read_val(
+ base + '.minLCInterval', 360))
+ max_lc_interval = (_ba.get_account_misc_read_val(
+ base + '.maxLCInterval', 300))
+ if launch_count < min_lc:
+ lc_amt = 0.0
+ elif launch_count > max_lc:
+ lc_amt = 1.0
+ else:
+ lc_amt = ((float(launch_count) - min_lc) /
+ (max_lc - min_lc))
+ incr = (1.0 - lc_amt) * min_lc_scale + lc_amt * max_lc_scale
+ interval = ((1.0 - lc_amt) * min_lc_interval +
+ lc_amt * max_lc_interval)
+ self.ad_amt += incr
+ assert self.ad_amt is not None
+ if self.ad_amt >= 1.0:
+ self.ad_amt = self.ad_amt % 1.0
+ self.attempted_first_ad = True
+
+ # After we've reached the traditional show-threshold once,
+ # try again whenever its been INTERVAL since our last successful
+ # show.
+ elif (
+ self.attempted_first_ad and
+ (self.last_ad_completion_time is None or
+ (interval is not None
+ and _ba.time(TimeType.REAL) - self.last_ad_completion_time >
+ (interval * interval_mult)))):
+ # Reset our other counter too in this case.
+ self.ad_amt = 0.0
+ else:
+ show = False
+
+ # If we're *still* cleared to show, actually tell the system to show.
+ if show:
+ # As a safety-check, set up an object that will run
+ # the completion callback if we've returned and sat for 10 seconds
+ # (in case some random ad network doesn't properly deliver its
+ # completion callback).
+ class _Payload:
+
+ def __init__(self, pcall: Callable[[], Any]):
+ self._call = pcall
+ self._ran = False
+
+ def run(self, fallback: bool = False) -> None:
+ """Run fallback call (and issue a warning about it)."""
+ if not self._ran:
+ if fallback:
+ print(
+ ('ERROR: relying on fallback ad-callback! '
+ 'last network: ' + app.ads.last_ad_network +
+ ' (set ' + str(
+ int(time.time() -
+ app.ads.last_ad_network_set_time)) +
+ 's ago); purpose=' + app.ads.last_ad_purpose))
+ _ba.pushcall(self._call)
+ self._ran = True
+
+ payload = _Payload(call)
+ with _ba.Context('ui'):
+ _ba.timer(5.0,
+ lambda: payload.run(fallback=True),
+ timetype=TimeType.REAL)
+ self.show_ad('between_game', on_completion_call=payload.run)
+ else:
+ _ba.pushcall(call) # Just run the callback without the ad.
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..27c89964
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_analytics.py
@@ -0,0 +1,73 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""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.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')
+ 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.getname())
+ _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.getname())
+ _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/_app.py b/assets/src/ba_data/python/ba/_app.py
index 9ca5def9..47b19fdf 100644
--- a/assets/src/ba_data/python/ba/_app.py
+++ b/assets/src/ba_data/python/ba/_app.py
@@ -1,35 +1,23 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-import time
+import random
from typing import TYPE_CHECKING
import _ba
+from ba._music import MusicSubsystem
+from ba._language import LanguageSubsystem
+from ba._ui import UISubsystem
+from ba._achievement import AchievementSubsystem
+from ba._plugin import PluginSubsystem
+from ba._account import AccountSubsystem
+from ba._meta import MetadataSubsystem
+from ba._ads import AdsSubsystem
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
@@ -37,7 +25,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.
@@ -46,11 +34,6 @@ class App:
"""
# pylint: disable=too-many-public-methods
- # Note: many values here are simple method attrs and thus don't show
- # up in docs. If there's any that'd be useful to expose publicly, they
- # should be converted to properties so its possible to validate values
- # and provide docs.
-
@property
def build_number(self) -> int:
"""Integer build number.
@@ -58,96 +41,20 @@ 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
-
- @property
- def locale(self) -> str:
- """Raw country/language code detected by the game (such as 'en_US').
-
- Generally for language-specific code you should look at
- 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
-
- def can_display_language(self, language: str) -> bool:
- """Tell whether we can display a particular language.
-
- (internal)
-
- On some platforms we don't have unicode rendering yet
- which limits the languages we can draw.
- """
-
- # We don't yet support full unicode display on windows or linux :-(.
- if (language in {
- 'Chinese', 'ChineseTraditional', 'Persian', 'Korean', 'Arabic',
- 'Hindi', 'Vietnamese'
- } and self.platform in ('windows', 'linux')):
- return False
- return True
-
- def _get_default_language(self) -> str:
- languages = {
- 'de': 'German',
- 'es': 'Spanish',
- 'sk': 'Slovak',
- 'it': 'Italian',
- 'nl': 'Dutch',
- 'da': 'Danish',
- 'pt': 'Portuguese',
- 'fr': 'French',
- 'el': 'Greek',
- 'ru': 'Russian',
- 'pl': 'Polish',
- 'sv': 'Swedish',
- 'eo': 'Esperanto',
- 'cs': 'Czech',
- 'hr': 'Croatian',
- 'hu': 'Hungarian',
- 'be': 'Belarussian',
- 'ro': 'Romanian',
- 'ko': 'Korean',
- 'fa': 'Persian',
- 'ar': 'Arabic',
- 'zh': 'Chinese',
- 'tr': 'Turkish',
- 'id': 'Indonesian',
- 'sr': 'Serbian',
- 'uk': 'Ukrainian',
- 'vi': 'Vietnamese',
- 'hi': 'Hindi'
- }
-
- # Special case Chinese: specific variations map to traditional.
- # (otherwise will map to 'Chinese' which is simplified)
- if self.locale in ('zh_HANT', 'zh_TW'):
- language = 'ChineseTraditional'
- else:
- language = languages.get(self.locale[:2], 'English')
- if not self.can_display_language(language):
- language = 'English'
- return language
-
- @property
- def language(self) -> str:
- """The name of the language the game is running in.
-
- This can be selected explicitly by the user or may be set
- automatically based on ba.App.locale or other factors.
- """
- assert isinstance(self.config, dict)
- return self.config.get('Lang', self.default_language)
+ assert isinstance(self._env['config_file_path'], str)
+ return self._env['config_file_path']
@property
def user_agent_string(self) -> str:
"""String containing various bits of info about OS/device/etc."""
- return self._user_agent_string
+ assert isinstance(self._env['user_agent_string'], str)
+ return self._env['user_agent_string']
@property
def version(self) -> str:
@@ -157,7 +64,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:
@@ -167,7 +75,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:
@@ -176,22 +85,26 @@ 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_ba(self) -> str:
+ def python_directory_app(self) -> str:
"""Path where the app looks for its bundled scripts."""
- return self._python_directory_ba
+ assert isinstance(self._env['python_directory_app'], str)
+ return self._env['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
+ assert isinstance(self._env['python_directory_app_site'], str)
+ return self._env['python_directory_app_site']
@property
def config(self) -> ba.AppConfig:
@@ -205,7 +118,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:
@@ -214,43 +128,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 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
-
@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]:
@@ -267,7 +171,6 @@ class App:
the single shared instance.
"""
# pylint: disable=too-many-statements
- from ba._music import MusicController
# Config.
self.config_file_healthy = False
@@ -277,68 +180,31 @@ 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_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._platform: str = env['platform']
- 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._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.kiosk_mode: bool = env['kiosk_mode']
- assert isinstance(self.kiosk_mode, bool)
- self.headless_build: bool = env['headless_build']
- assert isinstance(self.headless_build, bool)
+ self.demo_mode: bool = self._env['demo_mode']
+ assert isinstance(self.demo_mode, bool)
+ self.arcade_mode: bool = self._env['arcade_mode']
+ assert isinstance(self.arcade_mode, 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.iircade_mode, bool)
+ self.allow_ticket_purchases: bool = not self.iircade_mode
# Misc.
- self.default_language = self._get_default_language()
- 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
self.ran_on_app_launch = False
- # If we try to run promo-codes due to launch-args/etc we might
- # not be signed in yet; go ahead and queue them up in that case.
- self.pending_promo_codes: List[str] = []
- self.last_in_game_ad_remove_message_show_time: Optional[float] = None
self.log_have_new = False
self.log_upload_timer_started = False
self._config: Optional[ba.AppConfig] = None
self.printed_live_object_warning = False
- self.last_post_purchase_message_time: Optional[float] = None
# We include this extra hash with shared input-mapping names so
# that we don't share mappings between differently-configured
@@ -353,30 +219,18 @@ class App:
# Server Mode.
self.server: Optional[ba.ServerController] = None
- # Ads.
- self.last_ad_network = 'unknown'
- self.last_ad_network_set_time = time.time()
- self.ad_amt: Optional[float] = None
- self.last_ad_purpose = 'invalid'
- self.attempted_first_ad = False
-
- # Music.
- self.music = MusicController()
-
- # Language.
- self.language_target: Optional[_lang.AttrDict] = None
- self.language_merged: Optional[_lang.AttrDict] = None
-
- # Achievements.
- self.achievements: List[ba.Achievement] = []
- self.achievements_to_display: (List[Tuple[ba.Achievement, bool]]) = []
- self.achievement_display_timer: Optional[_ba.Timer] = None
- self.last_achievement_display_time: float = 0.0
- self.achievement_completion_banner_slots: Set[int] = set()
+ self.meta = MetadataSubsystem()
+ self.accounts = AccountSubsystem()
+ self.plugins = PluginSubsystem()
+ self.music = MusicSubsystem()
+ self.lang = LanguageSubsystem()
+ self.ach = AchievementSubsystem()
+ self.ui = UISubsystem()
+ self.ads = AdsSubsystem()
# 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.
@@ -395,61 +249,31 @@ class App:
self.ffa_series_length = 24
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.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 = {}
- self.tournament_info: Dict = {}
- self.account_tournament_list: Optional[Tuple[int, List[str]]] = None
self.ping_thread_count = 0
self.invite_confirm_windows: List[Any] = [] # FIXME: Don't use Any.
self.store_layout: Optional[Dict[str, List[Dict[str, Any]]]] = None
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.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.
(internal)"""
- # FIXME: Break this up.
- # pylint: disable=too-many-statements
# pylint: disable=too-many-locals
# 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
from ba import _campaign
from bastd import appdelegate
from bastd import maps as stdmaps
@@ -460,8 +284,8 @@ class App:
self.delegate = appdelegate.AppDelegate()
- self.uicontroller = UIController()
- _achievement.init_achievements()
+ self.ui.on_app_launch()
+
spazappearance.register_appearances()
_campaign.init_campaigns()
@@ -476,58 +300,15 @@ 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).
- # 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,
- ui_upkeep,
- 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))
-
- 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))
-
- # If there's a leftover log file, attempt to upload
- # it to the server and/or get rid of it.
+ # 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()
- 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;
- # need to just add a proper call to query this.
- # if env['python_directory_ba'] != '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.
@@ -554,21 +335,24 @@ 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,
- lambda: _ba.screenmessage('Note: using local server',
- (1, 1, 0),
- log=True),
+ lambda: _ba.screenmessage(
+ 'Note: using local server',
+ (1, 1, 0),
+ log=True,
+ ),
timetype=TimeType.REAL)
elif 'test' in server_addr:
- _ba.timer(
- 2.0,
- lambda: _ba.screenmessage('Note: using test server-module',
- (1, 1, 0),
- log=True),
- timetype=TimeType.REAL)
+ _ba.timer(2.0,
+ lambda: _ba.screenmessage(
+ 'Note: using test server-module',
+ (1, 1, 0),
+ log=True,
+ ),
+ timetype=TimeType.REAL)
cfg['launchCount'] = launch_count
cfg.commit()
@@ -576,27 +360,19 @@ class App:
# Run a test in a few seconds to see if we should pop up an existing
# pending special offer.
def check_special_offer() -> None:
- from bastd.ui import specialoffer
+ from bastd.ui.specialoffer import show_offer
config = self.config
if ('pendingSpecialOffer' in config and _ba.get_public_login_id()
== config['pendingSpecialOffer']['a']):
self.special_offer = config['pendingSpecialOffer']['o']
- specialoffer.show_offer()
+ 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.
- _meta.start_scan()
-
- # 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':
- _ba.sign_in('Local')
-
- _ba.pushcall(do_auto_sign_in)
+ self.meta.on_app_launch()
+ self.accounts.on_app_launch()
+ self.plugins.on_app_launch()
self.ran_on_app_launch = True
@@ -617,26 +393,27 @@ class App:
activity: Optional[ba.Activity] = _ba.get_foreground_host_activity()
if (activity is not None and activity.allow_pausing
and not _ba.have_connected_clients()):
- from ba import _gameutils, _lang
+ from ba import _gameutils
+ from ba._language import Lstr
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):
- globs = _gameutils.sharedobj('globals')
+ globs = activity.globalsnode
if not globs.paused:
_ba.playsound(_ba.getsound('refWhistle'))
globs.paused = True
# FIXME: This should not be an attr on Actor.
activity.paused_text = NodeActor(
- _ba.newnode(
- 'text',
- attrs={
- 'text': _lang.Lstr(resource='pausedByHostText'),
- 'client_only': True,
- 'flatness': 1.0,
- 'h_align': 'center'
- }))
+ _ba.newnode('text',
+ attrs={
+ 'text': Lstr(resource='pausedByHostText'),
+ 'client_only': True,
+ 'flatness': 1.0,
+ 'h_align': 'center'
+ }))
def resume(self) -> None:
"""Resume the game due to a user request or menu closing.
@@ -644,14 +421,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
@@ -659,13 +435,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.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
# so fade back in.
@@ -697,7 +476,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:
@@ -709,41 +488,35 @@ class App:
def on_app_resume(self) -> None:
"""Run when the app resumes from a suspended state."""
- self.music.on_app_resume()
-
self.fg_state += 1
-
- # Mark our cached tourneys as invalid so anyone using them knows
- # they might be out of date.
- for entry in list(self.tournament_info.values()):
- entry['valid'] = False
+ self.accounts.on_app_resume()
+ self.music.on_app_resume()
def launch_coop_game(self,
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 ba._campaign import getcampaign
from bastd.ui.coop.level import CoopLevelLockedWindow
if args is None:
args = {}
if game == '':
- raise Exception('empty game name')
+ 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.
@@ -767,65 +540,17 @@ class App:
_ba.fade_screen(False, endcall=_fade_end)
return True
- def do_remove_in_game_ads_message(self) -> None:
- """(internal)"""
- from ba._lang import Lstr
- from ba._enums import TimeType
-
- # Print this message once every 10 minutes at most.
- tval = _ba.time(TimeType.REAL)
- if (self.last_in_game_ad_remove_message_show_time is None or
- (tval - self.last_in_game_ad_remove_message_show_time > 60 * 10)):
- self.last_in_game_ad_remove_message_show_time = tval
- with _ba.Context('ui'):
- _ba.timer(
- 1.0,
- lambda: _ba.screenmessage(Lstr(
- resource='removeInGameAdsText',
- subs=[('${PRO}',
- Lstr(resource='store.bombSquadProNameText')),
- ('${APP_NAME}', Lstr(resource='titleText'))]),
- color=(1, 1, 0)),
- timetype=TimeType.REAL)
-
- def shutdown(self) -> None:
+ def on_app_shutdown(self) -> None:
"""(internal)"""
self.music.on_app_shutdown()
def handle_deep_link(self, url: str) -> None:
"""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/', '')
-
- # 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
- # few seconds.
- if _ba.get_account_state() != 'signed_in':
-
- def check_pending_codes() -> None:
- """(internal)"""
-
- # If we're still not signed in and have pending codes,
- # inform the user that they need to sign in to use them.
- if _ba.app.pending_promo_codes:
- _ba.screenmessage(
- Lstr(resource='signInForPromoCodeText'),
- color=(1, 0, 0))
- _ba.playsound(_ba.getsound('error'))
-
- _ba.app.pending_promo_codes.append(code)
- _ba.timer(6.0, check_pending_codes, timetype=TimeType.REAL)
- return
- _ba.screenmessage(Lstr(resource='submittingPromoCodeText'),
- color=(0, 1, 0))
- _ba.add_transaction({
- 'type': 'PROMO_CODE',
- 'expire_time': time.time() + 5,
- 'code': code
- })
- _ba.run_transactions()
+ from ba._language import Lstr
+ appname = _ba.appname()
+ if url.startswith(f'{appname}://code/'):
+ code = url.replace(f'{appname}://code/', '')
+ self.accounts.add_pending_promo_code(code)
else:
_ba.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
_ba.playsound(_ba.getsound('error'))
@@ -833,7 +558,7 @@ class App:
def _test_https(self) -> None:
"""Testing https support.
- (would be nice to get this working on our custom python builds; need
+ (would be nice to get this working on our custom Python builds; need
to wrangle certificates somehow).
"""
import urllib.request
diff --git a/assets/src/ba_data/python/ba/_appconfig.py b/assets/src/ba_data/python/ba/_appconfig.py
index 55f94943..ceb7c753 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
@@ -42,7 +24,7 @@ class AppConfig(dict):
AppConfig data is stored as json on disk on so make sure to only place
json-friendly values in it (dict, list, str, float, int, bool).
- Be aware that tuples will be quietly converted to lists.
+ Be aware that tuples will be quietly converted to lists when stored.
"""
def resolve(self, key: str) -> Any:
@@ -149,7 +131,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/ba/_appdelegate.py b/assets/src/ba_data/python/ba/_appdelegate.py
index b3d7c768..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
@@ -34,17 +16,16 @@ 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]]],
- None]) -> None:
+ 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_config_ui needs to be overridden")
+ "create_default_game_settings_ui needs to be overridden")
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 25a77d7d..f3698a4e 100644
--- a/assets/src/ba_data/python/ba/_apputils.py
+++ b/assets/src/ba_data/python/ba/_apputils.py
@@ -1,26 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
+import gc
import os
from typing import TYPE_CHECKING
@@ -43,7 +26,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.
@@ -58,8 +41,8 @@ def is_browser_likely_available() -> bool:
def get_remote_app_name() -> ba.Lstr:
"""(internal)"""
- from ba import _lang
- return _lang.Lstr(resource='remote_app.app_name')
+ from ba import _language
+ return _language.Lstr(resource='remote_app.app_name')
def should_submit_debug_info() -> bool:
@@ -67,60 +50,51 @@ 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.screenmessage("Suppressing debug reports.", color=(1, 0, 0))
- _ba.app.suppress_debug_reports = True
-
-
def handle_log() -> None:
"""Called on debug log prints.
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
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.get_log(),
- '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()
+
+ master_server_post('bsLog', info, response)
app.log_upload_timer_started = True
@@ -145,31 +119,40 @@ 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 master_server_post
- 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())
+ master_server_post('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:
- """Run an explicit pass of garbage collection."""
- import gc
+def garbage_collect_session_end() -> None:
+ """Run explicit garbage collection with extra checks for session end."""
gc.collect()
# Can be handy to print this to check for leaks between games.
@@ -179,8 +162,19 @@ def garbage_collect(session_end: bool = True) -> None:
print('PYTHON GC FOUND', len(gc.garbage), 'UNCOLLECTIBLE OBJECTS:')
for i, obj in enumerate(gc.garbage):
print(str(i) + ':', obj)
- if session_end:
- print_live_object_warnings('after session shutdown')
+ print_live_object_warnings('after session shutdown')
+
+
+def garbage_collect() -> None:
+ """Run an explicit pass of garbage collection.
+
+ category: General Utility Functions
+
+ May also print warnings/etc. if collection takes too long or if
+ uncollectible objects are found (so use this instead of simply
+ gc.collect().
+ """
+ gc.collect()
def print_live_object_warnings(when: Any,
@@ -188,22 +182,24 @@ def print_live_object_warnings(when: Any,
ignore_activity: ba.Activity = None) -> None:
"""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,210 +207,32 @@ 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:
"""Print an error if a corrupt file is found."""
- from ba._lang import get_resource
from ba._general import Call
from ba._enums import TimeType
- _ba.timer(
- 2.0,
- lambda: _ba.screenmessage(get_resource('internal.corruptFileText').
- replace('${EMAIL}', 'support@froemling.net'),
- color=(1, 0, 0)),
- timetype=TimeType.REAL)
+ _ba.timer(2.0,
+ lambda: _ba.screenmessage(
+ _ba.app.lang.get_resource('internal.corruptFileText').
+ replace('${EMAIL}', 'support@froemling.net'),
+ color=(1, 0, 0),
+ ),
+ timetype=TimeType.REAL)
_ba.timer(2.0,
Call(_ba.playsound, _ba.getsound('error')),
timetype=TimeType.REAL)
-
-
-def show_ad(purpose: str,
- on_completion_call: Callable[[], Any] = None) -> None:
- """(internal)"""
- _ba.app.last_ad_purpose = purpose
- _ba.show_ad(purpose, on_completion_call)
-
-
-def show_ad_2(purpose: str,
- on_completion_call: Callable[[bool], Any] = None) -> None:
- """(internal)"""
- _ba.app.last_ad_purpose = purpose
- _ba.show_ad_2(purpose, on_completion_call)
-
-
-def call_after_ad(call: Callable[[], Any]) -> None:
- """Run a call after potentially showing an ad."""
- # pylint: disable=too-many-statements
- # pylint: disable=too-many-branches
- # pylint: disable=too-many-locals
- from ba._account import have_pro
- from ba._enums import TimeType
- import time
- app = _ba.app
- show = True
-
- # No ads without net-connections, etc.
- if not _ba.can_show_ad():
- show = False
- if have_pro():
- show = False # Pro disables interstitials.
- try:
- session = _ba.get_foreground_host_session()
- assert session is not None
- is_tournament = session.tournament_id is not None
- except Exception:
- is_tournament = False
- if is_tournament:
- show = False # Never show ads during tournaments.
-
- if show:
- interval: Optional[float]
- launch_count = app.config.get('launchCount', 0)
-
- # If we're seeing short ads we may want to space them differently.
- interval_mult = (_ba.get_account_misc_read_val(
- 'ads.shortIntervalMult', 1.0) if app.last_ad_was_short else 1.0)
- if app.ad_amt is None:
- if launch_count <= 1:
- app.ad_amt = _ba.get_account_misc_read_val(
- 'ads.startVal1', 0.99)
- else:
- app.ad_amt = _ba.get_account_misc_read_val(
- 'ads.startVal2', 1.0)
- interval = None
- else:
- # So far we're cleared to show; now calc our ad-show-threshold and
- # see if we should *actually* show (we reach our threshold faster
- # the longer we've been playing).
- base = 'ads' if _ba.has_video_ads() else 'ads2'
- min_lc = _ba.get_account_misc_read_val(base + '.minLC', 0.0)
- max_lc = _ba.get_account_misc_read_val(base + '.maxLC', 5.0)
- min_lc_scale = (_ba.get_account_misc_read_val(
- base + '.minLCScale', 0.25))
- max_lc_scale = (_ba.get_account_misc_read_val(
- base + '.maxLCScale', 0.34))
- min_lc_interval = (_ba.get_account_misc_read_val(
- base + '.minLCInterval', 360))
- max_lc_interval = (_ba.get_account_misc_read_val(
- base + '.maxLCInterval', 300))
- if launch_count < min_lc:
- lc_amt = 0.0
- elif launch_count > max_lc:
- lc_amt = 1.0
- else:
- lc_amt = ((float(launch_count) - min_lc) / (max_lc - min_lc))
- incr = (1.0 - lc_amt) * min_lc_scale + lc_amt * max_lc_scale
- interval = ((1.0 - lc_amt) * min_lc_interval +
- lc_amt * max_lc_interval)
- app.ad_amt += incr
- assert app.ad_amt is not None
- if app.ad_amt >= 1.0:
- app.ad_amt = app.ad_amt % 1.0
- app.attempted_first_ad = True
-
- # After we've reached the traditional show-threshold once,
- # try again whenever its been INTERVAL since our last successful show.
- elif (app.attempted_first_ad
- and (app.last_ad_completion_time is None or
- (interval is not None
- and _ba.time(TimeType.REAL) - app.last_ad_completion_time >
- (interval * interval_mult)))):
- # Reset our other counter too in this case.
- app.ad_amt = 0.0
- else:
- show = False
-
- # If we're *still* cleared to show, actually tell the system to show.
- if show:
- # As a safety-check, set up an object that will run
- # the completion callback if we've returned and sat for 10 seconds
- # (in case some random ad network doesn't properly deliver its
- # completion callback).
- class _Payload:
-
- def __init__(self, pcall: Callable[[], Any]):
- self._call = pcall
- self._ran = False
-
- def run(self, fallback: bool = False) -> None:
- """Run the fallback call (and issues a warning about it)."""
- if not self._ran:
- if fallback:
- print((
- 'ERROR: relying on fallback ad-callback! '
- 'last network: ' + app.last_ad_network + ' (set ' +
- str(int(time.time() -
- app.last_ad_network_set_time)) +
- 's ago); purpose=' + app.last_ad_purpose))
- _ba.pushcall(self._call)
- self._ran = True
-
- payload = _Payload(call)
- with _ba.Context('ui'):
- _ba.timer(5.0,
- lambda: payload.run(fallback=True),
- timetype=TimeType.REAL)
- show_ad('between_game', on_completion_call=payload.run)
- else:
- _ba.pushcall(call) # Just run the callback without the ad.
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 e31ee809..070b022d 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
@@ -42,7 +24,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)
@@ -53,7 +35,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.newactivity(tutorial.TutorialActivity))
def __del__(self) -> None:
@@ -62,7 +44,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')
@@ -73,12 +55,12 @@ 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(
'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({
@@ -90,8 +72,8 @@ 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() +
- '/stressTestStats.csv')),
+ modutils.get_human_readable_user_scripts_path() +
+ '/stress_test_stats.csv')),
timetype=TimeType.REAL)
@@ -112,7 +94,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 +104,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)),
@@ -169,13 +151,14 @@ def run_media_reload_benchmark() -> None:
def delay_add(start_time: float) -> None:
def doit(start_time_2: float) -> None:
- from ba import _lang
_ba.screenmessage(
- _lang.get_resource('debugWindow.totalReloadTimeText').replace(
- '${TIME}', str(_ba.time(TimeType.REAL) - start_time_2)))
+ _ba.app.lang.get_resource(
+ 'debugWindow.totalReloadTimeText').replace(
+ '${TIME}',
+ str(_ba.time(TimeType.REAL) - start_time_2)))
_ba.print_load_info()
if _ba.app.config.resolve('Texture Quality') != 'High':
- _ba.screenmessage(_lang.get_resource(
+ _ba.screenmessage(_ba.app.lang.get_resource(
'debugWindow.reloadBenchmarkBestResultsText'),
color=(1, 1, 0))
diff --git a/assets/src/ba_data/python/ba/_campaign.py b/assets/src/ba_data/python/ba/_campaign.py
index 3beb4dca..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
@@ -35,7 +17,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,24 +43,27 @@ 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 Exception('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:
if level.name == name:
return level
- raise Exception("Level '" + name + "' not found in campaign '" +
- self.name + "'")
+ raise _error.NotFoundError("Level '" + name +
+ "' not found in campaign '" + self.name +
+ "'")
def reset(self) -> None:
"""Reset state for the Campaign."""
@@ -87,14 +72,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(
@@ -118,50 +104,53 @@ 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')
- 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'},
@@ -170,52 +159,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={},
@@ -224,17 +213,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,
@@ -244,7 +233,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,
@@ -254,7 +243,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,
@@ -265,55 +254,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,
@@ -323,38 +312,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/_collision.py b/assets/src/ba_data/python/ba/_collision.py
new file mode 100644
index 00000000..e9db1e8e
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_collision.py
@@ -0,0 +1,72 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""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.
+
+ Category: Gameplay Classes
+ """
+
+ @property
+ def position(self) -> ba.Vec3:
+ """The position of the current collision."""
+ return _ba.Vec3(_ba.get_collision_info('position'))
+
+ @property
+ 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('sourcenode')
+ assert isinstance(node, (_ba.Node, type(None)))
+ if not node:
+ raise NodeNotFoundError()
+ return node
+
+ @property
+ 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('opposingnode')
+ assert isinstance(node, (_ba.Node, type(None)))
+ if not node:
+ raise NodeNotFoundError()
+ return node
+
+ @property
+ def opposingbody(self) -> int:
+ """The body index on the opposing node in the current collision."""
+ body = _ba.get_collision_info('opposingbody')
+ assert isinstance(body, int)
+ return body
+
+
+# Simply recycle one instance...
+_collision = Collision()
+
+
+def getcollision() -> Collision:
+ """Return the in-progress collision.
+
+ Category: Gameplay Functions
+ """
+ return _collision
diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py
index b48187a2..ae7adca9 100644
--- a/assets/src/ba_data/python/ba/_coopgame.py
+++ b/assets/src/ba_data/python/ba/_coopgame.py
@@ -1,49 +1,38 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-from typing import TYPE_CHECKING
+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
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
"""
+ # 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]):
+ def __init__(self, settings: dict):
super().__init__(settings)
# Cache these for efficiency.
@@ -54,32 +43,31 @@ class CoopGameActivity(GameActivity):
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))
+ 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.
- _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()
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(
+ 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,
- _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
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
@@ -87,7 +75,7 @@ class CoopGameActivity(GameActivity):
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:
@@ -116,7 +104,7 @@ class CoopGameActivity(GameActivity):
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:
"""
@@ -126,7 +114,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.
@@ -141,26 +130,24 @@ class CoopGameActivity(GameActivity):
player.actor.handlemessage(CelebrateMessage(duration))
def _preload_achievements(self) -> None:
- from ba import _achievement
- achievements = _achievement.get_achievements_for_coop_level(
+ achievements = _ba.app.ach.achievements_for_coop_level(
self._get_coop_level_name())
for ach in achievements:
ach.get_icon_texture(True)
def _show_remaining_achievements(self) -> None:
# pylint: disable=cyclic-import
- from ba import _achievement
- from ba import _lang
+ from ba._language 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 _ba.app.ach.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,
@@ -186,7 +173,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."""
@@ -204,12 +191,11 @@ class CoopGameActivity(GameActivity):
Returns True if a banner will be shown;
False otherwise
"""
- from ba import _achievement
if achievement_name in self._achievements_awarded:
return
- ach = _achievement.get_achievement(achievement_name)
+ ach = _ba.app.ach.get_achievement(achievement_name)
# If we're in the easy campaign and this achievement is hard-mode-only,
# ignore it.
@@ -219,8 +205,8 @@ class CoopGameActivity(GameActivity):
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
@@ -243,7 +229,7 @@ class CoopGameActivity(GameActivity):
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],
@@ -253,14 +239,13 @@ class CoopGameActivity(GameActivity):
})
_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."""
- 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 d1c28fd0..6273f867 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
@@ -30,8 +12,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):
@@ -42,16 +24,28 @@ class CoopSession(Session):
These generally consist of 1-4 players against
the computer and include functionality such as
high score lists.
+
+ Attributes:
+
+ 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
- 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')
-
app = _ba.app
# If they passed in explicit min/max, honor that.
@@ -63,14 +57,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,32 +65,25 @@ 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']
- 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 = getcampaign(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
self._custom_menu_ui: List[Dict[str, Any]] = []
# Start our joining screen.
- self.set_activity(_ba.new_activity(CoopJoinActivity))
+ self.setactivity(_ba.newactivity(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:
@@ -114,28 +94,27 @@ 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.getlevel(self.campaign_level_name)
gametype = level.gametype
settings = level.get_settings()
# Make sure all settings the game expects are present.
- neededsettings = gametype.get_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)
+ newactivity = _ba.newactivity(gametype, settings)
assert isinstance(newactivity, GameActivity)
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_state['level'])
+ levels = self.campaign.levels
+ level = self.campaign.getlevel(self.campaign_level_name)
nextlevel: Optional[ba.Level]
if level.index < len(levels) - 1:
@@ -147,35 +126,35 @@ class CoopSession(Session):
settings = nextlevel.get_settings()
# Make sure all settings the game expects are present.
- neededsettings = gametype.get_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)
+ newactivity = _ba.newactivity(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
- 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
- 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))
@@ -192,7 +171,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:
@@ -213,7 +192,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,
@@ -229,13 +208,13 @@ 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
# 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)
@@ -250,29 +229,28 @@ class CoopSession(Session):
# pylint: disable=too-many-statements
# pylint: disable=cyclic-import
from ba._activitytypes import JoinActivity, TransitionActivity
- from ba._lang import Lstr
+ from ba._language 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
from bastd.activity.coopscore import CoopScoreScreen
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:
- 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).
- 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
@@ -284,9 +262,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
@@ -295,11 +273,11 @@ 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 not app.kiosk_mode):
+ and self.campaign_level_name == 'Onslaught Training'
+ and not (app.demo_mode or app.arcade_mode)):
if self._tutorial_activity is None:
- raise Exception('tutorial not preloaded properly')
- self.set_activity(self._tutorial_activity)
+ raise RuntimeError('Tutorial not preloaded properly.')
+ self.setactivity(self._tutorial_activity)
self._tutorial_activity = None
self._ran_tutorial_activity = True
self._custom_menu_ui = []
@@ -309,17 +287,17 @@ 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:
- self.stats.register_player(player)
- self.stats.set_activity(next_game)
+ self.stats.register_sessionplayer(player)
+ self.stats.setactivity(next_game)
- # Now flip the current activity.
- self.set_activity(next_game)
+ # 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':
@@ -339,34 +317,38 @@ 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.newactivity(TransitionActivity))
else:
- # Generic team games.
- if isinstance(results, TeamGameResults):
- player_info = results.get_player_info()
- score = results.get_team_score(results.get_teams()[0])
- fail_message = None
- score_order = ('decreasing' if results.get_lower_is_better()
- else 'increasing')
- if results.get_score_type() in ('seconds', 'milliseconds',
- 'time'):
- score_type = 'time'
+ playerinfos: List[ba.PlayerInfo]
- # Results contains milliseconds; ScoreScreen wants
- # hundredths; need to fix :-/
+ # Generic team games.
+ if isinstance(results, GameResults):
+ playerinfos = results.playerinfos
+ score = results.get_sessionteam_score(results.sessionteams[0])
+ fail_message = None
+ 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:
- score //= 10
+ if results.scoretype is ScoreType.SECONDS:
+ score *= 100
+ elif results.scoretype is ScoreType.MILLISECONDS:
+ score //= 10
+ else:
+ raise RuntimeError('FIXME')
else:
- if results.get_score_type() != 'points':
- print(("Unknown score type: '" +
- 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['player_info']
- if 'player_info' in results else None)
+ 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)
@@ -375,26 +357,31 @@ 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 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.
if outcome == 'restart':
# This will pop up back in the same round.
- self.set_activity(_ba.new_activity(TransitionActivity))
+ self.setactivity(_ba.newactivity(TransitionActivity))
else:
- self.set_activity(
- _ba.new_activity(
+ self.setactivity(
+ _ba.newactivity(
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_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/_dependency.py b/assets/src/ba_data/python/ba/_dependency.py
index 3cff9850..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
@@ -283,7 +265,7 @@ class DependencySet(Generic[T]):
# Watch for wacky infinite dep loops.
if recursion > 10:
- raise Exception('Max recursion reached')
+ raise RecursionError('Max recursion reached')
hashval = dep.get_hash()
@@ -422,8 +404,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/_dualteamsession.py b/assets/src/ba_data/python/ba/_dualteamsession.py
index a011e678..427e7063 100644
--- a/assets/src/ba_data/python/ba/_dualteamsession.py
+++ b/assets/src/ba_data/python/ba/_dualteamsession.py
@@ -1,41 +1,27 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
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
+
+ # 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'
@@ -44,29 +30,28 @@ class DualTeamSession(_multiteamsession.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.get_winners()
+ winnergroups = results.winnergroups
# If everyone has the same score, call it a draw.
- if len(winners) < 2:
- self.set_activity(_ba.new_activity(DrawScoreScreenActivity))
+ if len(winnergroups) < 2:
+ self.setactivity(_ba.newactivity(DrawScoreScreenActivity))
else:
- winner = winners[0].teams[0]
- winner.sessiondata['score'] += 1
+ winner = winnergroups[0].teams[0]
+ winner.customdata['score'] += 1
# If a team has won, show final victory screen.
- if winner.sessiondata['score'] >= (self._series_length -
- 1) / 2 + 1:
- self.set_activity(
- _ba.new_activity(TeamSeriesVictoryScoreScreenActivity,
- {'winner': winner}))
+ if winner.customdata['score'] >= (self._series_length - 1) / 2 + 1:
+ self.setactivity(
+ _ba.newactivity(TeamSeriesVictoryScoreScreenActivity,
+ {'winner': winner}))
else:
- self.set_activity(
- _ba.new_activity(TeamVictoryScoreScreenActivity,
- {'winner': winner}))
+ self.setactivity(
+ _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..7940bcfd 100644
--- a/assets/src/ba_data/python/ba/_enums.py
+++ b/assets/src/ba_data/python/ba/_enums.py
@@ -1,28 +1,67 @@
-# 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
+class InputType(Enum):
+ """Types of input a controller can send to the game.
+
+ Category: Enums
+
+ """
+ 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 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/_error.py b/assets/src/ba_data/python/ba/_error.py
index 5beb6936..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
@@ -31,16 +13,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.
@@ -59,6 +31,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.
@@ -73,6 +55,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 +69,20 @@ 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.
+
+ category: Exception Classes
+ """
+
+
class NodeNotFoundError(NotFoundError):
"""Exception raised when an expected ba.Node does not exist.
@@ -136,7 +139,7 @@ def print_exception(*args: Any, **keywds: Any) -> None:
if keywds:
allowed_keywds = ['once']
if any(keywd not in allowed_keywds for keywd in keywds):
- raise Exception('invalid keyword(s)')
+ raise TypeError('invalid keyword(s)')
try:
# If we're only printing once and already have, bail.
if keywds.get('once', False):
diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py
index 89c5c5c1..e81eb47d 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
@@ -37,7 +19,8 @@ class FreeForAllSession(MultiTeamSession):
Category: Gameplay Classes
"""
- _use_teams = False
+ use_teams = False
+ 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'
@@ -48,17 +31,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}
@@ -68,21 +51,21 @@ 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 efro.util import asserttype
from bastd.activity.drawscore import DrawScoreScreenActivity
from bastd.activity.multiteamvictory import (
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.
- if len(self.players) > 1 and len(winners) < 2:
- self.set_activity(
- _ba.new_activity(DrawScoreScreenActivity,
- {'results': results}))
+ if len(self.sessionplayers) > 1 and len(winners) < 2:
+ self.setactivity(
+ _ba.newactivity(DrawScoreScreenActivity, {'results': results}))
else:
# Award different point amounts based on number of players.
point_awards = self.get_ffa_point_awards()
@@ -90,24 +73,25 @@ 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
+ team for team in self.sessionteams
+ if team.customdata['score'] >= self._ffa_series_length
]
- series_winners.sort(reverse=True,
- key=lambda tm: (tm.sessiondata['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].sessiondata['score'] !=
- series_winners[1].sessiondata['score'])):
- self.set_activity(
- _ba.new_activity(TeamSeriesVictoryScoreScreenActivity,
- {'winner': series_winners[0]}))
+ and series_winners[0].customdata['score'] !=
+ series_winners[1].customdata['score'])):
+ self.setactivity(
+ _ba.newactivity(TeamSeriesVictoryScoreScreenActivity,
+ {'winner': series_winners[0]}))
else:
- self.set_activity(
- _ba.new_activity(FreeForAllVictoryScoreScreenActivity,
- {'results': results}))
+ self.setactivity(
+ _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 e9b16efd..1c1e7fbe 100644
--- a/assets/src/ba_data/python/ba/_gameactivity.py
+++ b/assets/src/ba_data/python/ba/_gameactivity.py
@@ -1,34 +1,22 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
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._lang import Lstr
+from ba._score import ScoreConfig
+from ba._language import Lstr
+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
+from ba import _map
if TYPE_CHECKING:
from typing import (List, Optional, Dict, Type, Any, Callable, Sequence,
@@ -37,116 +25,95 @@ 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
"""
# 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
+
+ # Default get_description() will return this if not None.
+ description: Optional[str] = None
+
+ # Default get_available_settings() will return this if not None.
+ available_settings: Optional[List[ba.Setting]] = None
+
+ # Default getscoreconfig() will return this if not None.
+ scoreconfig: Optional[ba.ScoreConfig] = 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_config_ui(
+ def create_settings_ui(
cls,
- sessionclass: Type[ba.Session],
- config: Optional[Dict[str, Any]],
- completion_call: Callable[[Optional[Dict[str, Any]]], None],
+ 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 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_settings() and ba.GameActivity.get_supported_maps()
- they can just rely on the default implementation here which calls those
- methods.
+ ba.GameActivity.get_available_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
- delegate.create_default_game_config_ui(cls, sessionclass, config,
- completion_call)
+ delegate.create_default_game_settings_ui(cls, sessiontype, settings,
+ 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 {}
+ 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())
@classmethod
- def get_resolved_score_info(cls) -> Dict[str, Any]:
+ def getname(cls) -> str:
+ """Return a str name for this game type.
+
+ This default implementation simply returns the 'name' class attr.
"""
- 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
-
- @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 cls.name if cls.name is not None else 'Untitled Game'
@classmethod
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
- # 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',
@@ -164,13 +131,14 @@ class GameActivity(Activity):
@classmethod
def get_description(cls, 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.
"""
- Subclasses should override this to return a description for this
- activity type (in English) within the context of the given
- ba.Session type.
- """
- del sessiontype # unused arg
- return ''
+ del sessiontype # Unused arg.
+ return cls.description if cls.description is not None else ''
@classmethod
def get_description_display_string(
@@ -183,88 +151,31 @@ class GameActivity(Activity):
return Lstr(translate=('gameDescriptions', description))
@classmethod
- def get_settings(
- cls,
- 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
- 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_settings() implementation for a capture-the-flag game:
- @classmethod
- def get_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
- })]
+ def get_available_settings(
+ cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]:
+ """Return a list of settings relevant to this game type when
+ running under the provided session type.
"""
del sessiontype # Unused arg.
- return []
+ return [] if cls.available_settings is None else cls.available_settings
@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.
"""
- from ba import _map
- del sessiontype # unused arg
+ del sessiontype # Unused arg.
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
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
@@ -296,46 +207,23 @@ class GameActivity(Activity):
# 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."""
- from ba import _map
super().__init__(settings)
- # 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
-
- # 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.initialplayerinfos: 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(map_name)
+ self._map_type = _map.get_map_class(self._calc_map_name(settings))
+
+ self._spawn_sound = _ba.getsound('spawn')
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
@@ -364,13 +252,12 @@ class GameActivity(Activity):
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
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.
@@ -385,11 +272,10 @@ class GameActivity(Activity):
if isinstance(self.session, CoopSession):
campaign = self.session.campaign
assert campaign is not None
- return campaign.get_level(
- self.session.campaign_state['level']).displayname
+ return campaign.getlevel(
+ 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]:
@@ -398,7 +284,7 @@ class GameActivity(Activity):
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;
@@ -406,11 +292,11 @@ class GameActivity(Activity):
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.
- 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
@@ -418,7 +304,7 @@ class GameActivity(Activity):
"""
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
@@ -432,11 +318,11 @@ class GameActivity(Activity):
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.
- 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
@@ -446,19 +332,15 @@ class GameActivity(Activity):
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
+ # 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
+ 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
@@ -501,15 +383,12 @@ class GameActivity(Activity):
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._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.
@@ -521,185 +400,112 @@ class GameActivity(Activity):
if isinstance(session, CoopSession):
assert session.campaign is not None
if session.campaign.sequential:
- gnode = _gameutils.sharedobj('globals')
+ gnode = self.globalsnode
# 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(
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 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
- campaign = session.campaign
- if isinstance(session, CoopSession):
- 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._analytics import game_begin_analytics
super().on_begin()
- try:
- self._game_begin_analytics()
- except Exception:
- from ba import _error
- _error.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 = [{
- 'name': p.get_name(full=True),
- 'character': p.character
- } for p in self.players]
+ 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.
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:
- from ba._account import cache_tournament_info
if data is not None:
data_t = data['t'] # This used to be the whole payload.
# Keep our cached tourney info up to date
- cache_tournament_info(data_t)
+ _ba.app.accounts.cache_tournament_info(data_t)
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:
- 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.
- # 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)
-
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.spaz.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.spaz.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,
kill=True,
victim_player=player,
importance=importance,
- showpoints=self._show_kill_points)
+ showpoints=self.show_kill_points)
+ else:
+ return super().handlemessage(msg)
+ return None
- 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
@@ -711,16 +517,16 @@ class GameActivity(Activity):
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
- sb_desc_in = self.get_instance_scoreboard_description()
+ # 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):
sb_desc_l = [sb_desc_in] # handle simple string case
else:
sb_desc_l = sb_desc_in
if not isinstance(sb_desc_l[0], str):
- raise Exception('Invalid format for instance description')
+ raise TypeError('Invalid format for instance description.')
is_empty = (sb_desc_l[0] == '')
subs = []
@@ -729,9 +535,7 @@ class GameActivity(Activity):
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
@@ -783,10 +587,9 @@ class GameActivity(Activity):
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,
@@ -808,15 +611,15 @@ class GameActivity(Activity):
else:
desc_l = desc_in
if not isinstance(desc_l[0], str):
- raise Exception('Invalid format for instance description')
+ raise TypeError('Invalid format for instance description')
subs = []
for i in range(len(desc_l) - 1):
subs.append(('${ARG' + str(i + 1) + '}', str(desc_l[i + 1])))
translation = Lstr(translate=('gameDescriptions', desc_l[0]),
subs=subs)
- # do some standard filters (epic mode, etc)
- if 'Epic Mode' in self.settings and self.settings['Epic Mode']:
+ # Do some standard filters (epic mode, etc).
+ if self.settings_raw.get('Epic Mode', False):
translation = Lstr(resource='epicDescriptionFilterText',
subs=[('${DESCRIPTION}', translation)])
vrmode = _ba.app.vr_mode
@@ -849,24 +652,23 @@ class GameActivity(Activity):
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..
+
+ # 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}:',
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)
- # a few subs..
+ # Do a few substitutions.
tip_lstr = Lstr(translate=('tips', tip),
subs=[('${PICKUP}',
_ba.charstr(SpecialChar.TOP_BUTTON))])
@@ -941,21 +743,21 @@ class GameActivity(Activity):
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 results is a standard team-game-results, associate it with us
+ # so it can grab our score prefs.
+ if isinstance(results, GameResults):
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
@@ -965,39 +767,18 @@ class GameActivity(Activity):
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;'
' your game should override this.')
- def spawn_player_if_exists(self, player: ba.Player) -> 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: ba.Player) -> ba.Actor:
- """Spawn *something* for the provided ba.Player.
-
- The default implementation simply calls spawn_player_spaz().
- """
- if not player:
- raise Exception('spawn_player() called for nonexistent player')
-
- 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,
@@ -1021,34 +802,52 @@ 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
+ # 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(
+ 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:
+ """
+ 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: 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."""
# 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
- name = player.get_name()
+ name = player.getname()
color = player.color
highlight = player.highlight
@@ -1059,13 +858,13 @@ class GameActivity(Activity):
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
# 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']
@@ -1080,7 +879,7 @@ class GameActivity(Activity):
# 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)
@@ -1090,30 +889,14 @@ class GameActivity(Activity):
_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 = {}
@@ -1121,27 +904,24 @@ class GameActivity(Activity):
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:
"""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:
@@ -1154,8 +934,6 @@ class GameActivity(Activity):
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._general import WeakCall
from ba._nodeactor import NodeActor
if duration <= 0.0:
return
@@ -1179,8 +957,9 @@ class GameActivity(Activity):
'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(
@@ -1229,16 +1008,16 @@ class GameActivity(Activity):
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:
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),
@@ -1366,3 +1145,21 @@ class GameActivity(Activity):
maxwidth=800,
trail=trail,
color=color).autoretain()
+
+ def _calc_map_name(self, settings: dict) -> 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/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py
index 46c484a4..9885b30f 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
@@ -26,9 +8,12 @@ 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:
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,12 +21,12 @@ 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:
+class GameResults:
"""
- Results for a completed ba.TeamGameActivity.
+ Results for a completed game.
Category: Gameplay Classes
@@ -50,135 +35,147 @@ 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._player_info: Optional[List[Dict[str, Any]]] = 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_name: Optional[str] = None
+ self._score_label: Optional[str] = None
self._none_is_winner: Optional[bool] = None
- self._score_type: Optional[str] = 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.')
+ raise RuntimeError('Game set twice for GameResults.')
self._game_set = True
- self._teams = [weakref.ref(team) for team in game.teams]
- score_info = game.get_resolved_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._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
+ 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: int) -> None:
- """Set the score for a given ba.Team.
+ def set_team_score(self, team: ba.Team, score: Optional[int]) -> None:
+ """Set the score for a given 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)
+ assert isinstance(team, Team)
+ sessionteam = team.sessionteam
+ self._scores[sessionteam.id] = (weakref.ref(sessionteam), score)
- def get_team_score(self, team: ba.Team) -> Optional[int]:
- """Return the score for a given team."""
+ 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 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.Team]:
- """Return all ba.Teams in the results."""
+ @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)
return teams
- def has_score_for_team(self, team: ba.Team) -> 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
+ 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, team: ba.Team) -> 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.)
"""
from ba._gameutils import timestring
- from ba._lang import Lstr
+ from ba._language 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[0]() is sessionteam:
if score[1] is None:
return Lstr(value='-')
- if self._score_type == 'seconds':
+ if self._scoretype is ScoreType.SECONDS:
return timestring(score[1] * 1000,
centi=False,
timeformat=TimeFormat.MILLISECONDS)
- if self._score_type == '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[Dict[str, Any]]:
+ @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) -> str:
- """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.")
- assert self._score_name is not None
- return self._score_name
+ 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.Team]:
- """Get the winning ba.Team if there is exactly one; None otherwise."""
+ @property
+ 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.")
- 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.")
# 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
@@ -190,21 +187,23 @@ class TeamGameResults:
assert team is not None
sval.append(team)
results: List[Tuple[Optional[int],
- List[ba.Team]]] = list(winners.items())
- results.sort(reverse=not self._lower_is_better, key=lambda x: x[0])
+ List[ba.SessionTeam]]] = list(winners.items())
+ results.sort(reverse=not self._lower_is_better,
+ key=lambda x: asserttype(x[0], int))
# Also group the 'None' scores.
- none_teams: List[ba.Team] = []
+ 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.Team]]] = [(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/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py
index acc8969a..89e73542 100644
--- a/assets/src/ba_data/python/ba/_gameutils.py
+++ b/assets/src/ba_data/python/ba/_gameutils.py
@@ -1,30 +1,15 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
+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:
from typing import Any, Dict, Sequence, Optional
@@ -40,6 +25,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:
@@ -47,125 +43,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: Optional[ba.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]
- except Exception:
- 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 Exception(
- "unrecognized shared object (activity context): '" + name +
- "'")
- else:
- session: Optional[ba.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 Exception('unrecognized shared object '
- "(session context): '" + name + "'")
- else:
- raise Exception('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],
@@ -194,11 +71,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)
- # noinspection PyUnresolvedReferences
- _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,
@@ -209,7 +85,7 @@ def animate(node: ba.Node,
elif timeformat is TimeFormat.MILLISECONDS:
mult = 1
else:
- raise Exception(f'invalid timeformat value: {timeformat}')
+ raise ValueError(f'invalid timeformat value: {timeformat}')
curve.times = [int(mult * time) for time, val in items]
curve.offset = _ba.time(timeformat=TimeFormat.MILLISECONDS) + int(
@@ -222,15 +98,20 @@ 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)
- # noinspection PyUnresolvedReferences
_ba.timer(int(mult * items[-1][0]) + 1000,
curve.delete,
timeformat=TimeFormat.MILLISECONDS)
# 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
@@ -261,25 +142,31 @@ 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)
- # noinspection PyUnresolvedReferences
- _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
elif timeformat is TimeFormat.MILLISECONDS:
mult = 1
else:
- raise Exception('invalid timeformat value: "' + str(timeformat) + '"')
+ 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(
@@ -291,7 +178,6 @@ def animate_array(node: ba.Node,
# curve after its done its job.
if not loop:
# (PyCharm seems to think item is a float, not a tuple)
- # noinspection PyUnresolvedReferences
_ba.timer(int(mult * items[-1][0]) + 1000,
curve.delete,
timeformat=TimeFormat.MILLISECONDS)
@@ -303,7 +189,6 @@ def animate_array(node: ba.Node,
# once we get disconnected.
if not loop:
# (PyCharm seems to think item is a float, not a tuple)
- # noinspection PyUnresolvedReferences
_ba.timer(int(mult * items[-1][0]) + 1000,
combine.delete,
timeformat=TimeFormat.MILLISECONDS)
@@ -321,7 +206,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.ui.uiscale is UIScale.SMALL or app.vr_mode
txtnode = _ba.newnode('text',
attrs={
'text': damage,
@@ -382,12 +267,13 @@ def timestring(timeval: float,
use a 'timedisplay' Node and attribute connections.
"""
- from ba._lang import Lstr
+ from ba._language import Lstr
# 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:
@@ -395,7 +281,7 @@ def timestring(timeval: float,
elif timeformat is TimeFormat.MILLISECONDS:
pass
else:
- raise Exception(f'invalid timeformat: {timeformat}')
+ raise ValueError(f'invalid timeformat: {timeformat}')
if not isinstance(timeval, int):
timeval = int(timeval)
bits = []
@@ -452,7 +338,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/_general.py b/assets/src/ba_data/python/ba/_general.py
index 73945d5d..57ad9a88 100644
--- a/assets/src/ba_data/python/ba/_general.py
+++ b/assets/src/ba_data/python/ba/_general.py
@@ -1,39 +1,62 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
+import gc
import types
import weakref
-from typing import TYPE_CHECKING, TypeVar
+import random
+import inspect
+from typing import TYPE_CHECKING, TypeVar, Protocol
+from efro.terminal import Clr
import _ba
+from ba._error import print_error, print_exception
+from ba._enums import TimeType
if TYPE_CHECKING:
- from typing import Any, Type
- from efro.call import Call
+ from types import FrameType
+ 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):
+ """A Protocol for objects supporting an exists() method.
+
+ Category: Protocols
+ """
+
+ 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 for any ba.Existable object.
+
+ 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 (Optional[FooType]) into functions expecting only live ones
+ (FooType), 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://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
+
+
def getclass(name: str, subclassof: Type[T]) -> Type[T]:
"""Given a full class name such as foo.bar.MyClass, return the class.
@@ -50,7 +73,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
@@ -68,27 +91,23 @@ 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
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()))
@@ -103,7 +122,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.
@@ -154,9 +172,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:
@@ -206,9 +225,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)
@@ -259,3 +279,132 @@ 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 print_active_refs(obj: Any) -> None:
+ """Print info about things referencing a given object.
+
+ Category: General Utility Functions
+
+ Useful for tracking down cyclical references and causes for zombie objects.
+ """
+ # pylint: disable=too-many-nested-blocks
+ from types import FrameType, TracebackType
+ refs = list(gc.get_referrers(obj))
+ print(f'{Clr.YLW}Active referrers to {obj}:{Clr.RST}')
+ for i, ref in enumerate(refs):
+ print(f'{Clr.YLW}#{i+1}:{Clr.BLU} {ref}{Clr.RST}')
+
+ # For certain types of objects such as stack frames, show what is
+ # keeping *them* alive too.
+ if isinstance(ref, FrameType):
+ print(f'{Clr.YLW} Active referrers to #{i+1}:{Clr.RST}')
+ refs2 = list(gc.get_referrers(ref))
+ for j, ref2 in enumerate(refs2):
+ print(f'{Clr.YLW} #a{j+1}:{Clr.BLU} {ref2}{Clr.RST}')
+
+ # Can go further down the rabbit-hole if needed...
+ if bool(False):
+ if isinstance(ref2, TracebackType):
+ print(f'{Clr.YLW} '
+ f'Active referrers to #a{j+1}:{Clr.RST}')
+ refs3 = list(gc.get_referrers(ref2))
+ for k, ref3 in enumerate(refs3):
+ print(f'{Clr.YLW} '
+ f'#b{k+1}:{Clr.BLU} {ref3}{Clr.RST}')
+
+ if isinstance(ref3, BaseException):
+ print(f'{Clr.YLW} Active referrers to'
+ f' #b{k+1}:{Clr.RST}')
+ refs4 = list(gc.get_referrers(ref3))
+ for x, ref4 in enumerate(refs4):
+ print(f'{Clr.YLW} #c{x+1}:{Clr.BLU}'
+ f' {ref4}{Clr.RST}')
+
+
+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 when expected to:'
+ f' {Clr.BLD}{obj}{Clr.RST}')
+ print_active_refs(obj)
+
+
+def storagename(suffix: str = None) -> str:
+ """Generate a unique name for storing class data in shared places.
+
+ Category: General Utility Functions
+
+ This consists of a leading underscore, the module path at the
+ call site with dots replaced by underscores, the containing class's
+ qualified name, and the provided suffix. When storing data in public
+ places such as 'customdata' dicts, this minimizes the chance of
+ collisions with other similarly named classes.
+
+ Note that this will function even if called in the class definition.
+
+ # Example: generate a unique name for storage purposes:
+ class MyThingie:
+
+ # This will give something like '_mymodule_submodule_mythingie_data'.
+ _STORENAME = ba.storagename('data')
+
+ # Use that name to store some data in the Activity we were passed.
+ def __init__(self, activity):
+ activity.customdata[self._STORENAME] = {}
+ """
+ frame = inspect.currentframe()
+ if frame is None:
+ raise RuntimeError('Cannot get current stack frame.')
+ fback = frame.f_back
+
+ # Note: We need to explicitly clear frame here to avoid a ref-loop
+ # that keeps all function-dicts in the stack alive until the next
+ # full GC cycle (the stack frame refers to this function's dict,
+ # which refers to the stack frame).
+ del frame
+
+ 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()}'
+ else:
+ fullpath = f'_{modulepath}'
+ if suffix is not None:
+ fullpath = f'{fullpath}_{suffix}'
+ return fullpath.replace('.', '_')
diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py
index fdafedd7..169a648f 100644
--- a/assets/src/ba_data/python/ba/_hooks.py
+++ b/assets/src/ba_data/python/ba/_hooks.py
@@ -1,31 +1,13 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-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
@@ -36,7 +18,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
@@ -58,31 +40,31 @@ def set_config_fullscreen_off() -> None:
def not_signed_in_screen_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(Lstr(resource='notSignedInErrorText'))
def connecting_to_party_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(Lstr(resource='internal.connectingToPartyText'),
color=(1, 1, 1))
def rejecting_invite_already_in_party_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(
Lstr(resource='internal.rejectingInviteAlreadyInPartyText'),
color=(1, 0.5, 0))
def connection_failed_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(Lstr(resource='internal.connectionFailedText'),
color=(1, 0.5, 0))
def temporarily_unavailable_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.playsound(_ba.getsound('error'))
_ba.screenmessage(
Lstr(resource='getTicketsWindow.unavailableTemporarilyText'),
@@ -90,20 +72,20 @@ def temporarily_unavailable_message() -> None:
def in_progress_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.playsound(_ba.getsound('error'))
_ba.screenmessage(Lstr(resource='getTicketsWindow.inProgressText'),
color=(1, 0, 0))
def error_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.playsound(_ba.getsound('error'))
_ba.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
def purchase_not_valid_error() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.playsound(_ba.getsound('error'))
_ba.screenmessage(Lstr(resource='store.purchaseNotValidError',
subs=[('${EMAIL}', 'support@froemling.net')]),
@@ -111,28 +93,28 @@ def purchase_not_valid_error() -> None:
def purchase_already_in_progress_error() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.playsound(_ba.getsound('error'))
_ba.screenmessage(Lstr(resource='store.purchaseAlreadyInProgressText'),
color=(1, 0, 0))
def gear_vr_controller_warning() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.playsound(_ba.getsound('error'))
_ba.screenmessage(Lstr(resource='usesExternalControllerText'),
color=(1, 0, 0))
def orientation_reset_cb_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(
Lstr(resource='internal.vrOrientationResetCardboardText'),
color=(0, 1, 0))
def orientation_reset_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(Lstr(resource='internal.vrOrientationResetText'),
color=(0, 1, 0))
@@ -151,18 +133,16 @@ def launch_main_menu_session() -> None:
def language_test_toggle() -> None:
- from ba._lang import setlanguage
- setlanguage('Gibberish' if _ba.app.language == 'English' else 'English')
+ _ba.app.lang.setlanguage('Gibberish' if _ba.app.lang.language ==
+ 'English' else 'English')
def award_in_control_achievement() -> None:
- from ba._achievement import award_local_achievement
- award_local_achievement('In Control')
+ _ba.app.ach.award_local_achievement('In Control')
def award_dual_wielding_achievement() -> None:
- from ba._achievement import award_local_achievement
- award_local_achievement('Dual Wielding')
+ _ba.app.ach.award_local_achievement('Dual Wielding')
def play_gong_sound() -> None:
@@ -174,19 +154,19 @@ def launch_coop_game(name: str) -> None:
def purchases_restored_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(Lstr(resource='getTicketsWindow.purchasesRestoredText'),
color=(0, 1, 0))
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()
def unavailable_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(Lstr(resource='getTicketsWindow.unavailableText'),
color=(1, 0, 0))
@@ -198,12 +178,12 @@ def submit_analytics_counts(sval: str) -> None:
def set_last_ad_network(sval: str) -> None:
import time
- _ba.app.last_ad_network = sval
- _ba.app.last_ad_network_set_time = time.time()
+ _ba.app.ads.last_ad_network = sval
+ _ba.app.ads.last_ad_network_set_time = time.time()
def no_game_circle_message() -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
_ba.screenmessage(Lstr(resource='noGameCircleText'), color=(1, 0, 0))
@@ -256,10 +236,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:
@@ -268,10 +248,13 @@ 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'))
+ from ba._language import Lstr
+
+ # 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:
@@ -280,7 +263,7 @@ def quit_window() -> None:
def remove_in_game_ads_message() -> None:
- _ba.app.do_remove_in_game_ads_message()
+ _ba.app.ads.do_remove_in_game_ads_message()
def telnet_access_request() -> None:
@@ -293,7 +276,7 @@ def do_quit() -> None:
def shutdown() -> None:
- _ba.app.shutdown()
+ _ba.app.on_app_shutdown()
def gc_disable() -> None:
@@ -303,11 +286,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,11 +321,16 @@ 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:
- 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/_input.py b/assets/src/ba_data/python/ba/_input.py
index b4d87cec..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
@@ -45,11 +27,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]:
@@ -562,8 +544,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(
@@ -621,15 +606,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/_keyboard.py b/assets/src/ba_data/python/ba/_keyboard.py
new file mode 100644
index 00000000..258125f5
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_keyboard.py
@@ -0,0 +1,35 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""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:
+ name
+ Displays when user selecting this keyboard.
+ chars
+ Used for row/column lengths.
+ pages
+ Extra chars like emojis.
+ nums
+ 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/ba/_lang.py b/assets/src/ba_data/python/ba/_lang.py
deleted file mode 100644
index 73664924..00000000
--- a/assets/src/ba_data/python/ba/_lang.py
+++ /dev/null
@@ -1,470 +0,0 @@
-# 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.
-# -----------------------------------------------------------------------------
-"""Language related functionality."""
-from __future__ import annotations
-
-import json
-import os
-from typing import TYPE_CHECKING, overload
-
-import _ba
-
-if TYPE_CHECKING:
- from typing import Any, Dict, List, Optional, Tuple, Union, Sequence
-
-
-class Lstr:
- """Used to define strings in a language-independent way.
-
- category: General Utility Classes
-
- These should be used whenever possible in place of hard-coded strings
- so that in-game or UI elements show up correctly on all clients in their
- currently-active language.
-
- To see available resource keys, look at any of the bs_language_*.py files
- in the game or the translations pages at bombsquadgame.com/translate.
-
- # EXAMPLE 1: specify a string from a resource path
- mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText')
-
- # EXAMPLE 2: specify a translated string via a category and english value;
- # if a translated value is available, it will be used; otherwise the
- # english value will be. To see available translation categories, look
- # under the 'translations' resource section.
- mynode.text = ba.Lstr(translate=('gameDescriptions', 'Defeat all enemies'))
-
- # EXAMPLE 3: specify a raw value and some substitutions. Substitutions can
- # be used with resource and translate modes as well.
- mynode.text = ba.Lstr(value='${A} / ${B}',
- subs=[('${A}', str(score)), ('${B}', str(total))])
-
- # EXAMPLE 4: Lstrs can be nested. This example would display the resource
- # at res_a but replace ${NAME} with the value of the resource at res_b
- mytextnode.text = ba.Lstr(resource='res_a',
- subs=[('${NAME}', ba.Lstr(resource='res_b'))])
- """
-
- # pylint: disable=redefined-outer-name, dangerous-default-value
- # noinspection PyDefaultArgument
- @overload
- def __init__(self,
- *,
- resource: str,
- fallback_resource: str = '',
- fallback_value: str = '',
- subs: Sequence[Tuple[str, Union[str, Lstr]]] = []) -> None:
- """Create an Lstr from a string resource."""
- ...
-
- # noinspection PyShadowingNames,PyDefaultArgument
- @overload
- def __init__(self,
- *,
- translate: Tuple[str, str],
- subs: Sequence[Tuple[str, Union[str, Lstr]]] = []) -> None:
- """Create an Lstr by translating a string in a category."""
- ...
-
- # noinspection PyDefaultArgument
- @overload
- def __init__(self,
- *,
- value: str,
- subs: Sequence[Tuple[str, Union[str, Lstr]]] = []) -> None:
- """Create an Lstr from a raw string value."""
- ...
-
- # pylint: enable=redefined-outer-name, dangerous-default-value
-
- def __init__(self, *args: Any, **keywds: Any) -> None:
- """Instantiate a Lstr.
-
- Pass a value for either 'resource', 'translate',
- or 'value'. (see Lstr help for examples).
- 'subs' can be a sequence of 2-member sequences consisting of values
- and replacements.
- 'fallback_resource' can be a resource key that will be used if the
- main one is not present for
- the current language in place of falling back to the english value
- ('resource' mode only).
- 'fallback_value' can be a literal string that will be used if neither
- the resource nor the fallback resource is found ('resource' mode only).
- """
- # pylint: disable=too-many-branches
- if args:
- raise Exception('Lstr accepts only keyword arguments')
-
- # Basically just store the exact args they passed.
- # However if they passed any Lstr values for subs,
- # replace them with that Lstr's dict.
- self.args = keywds
- our_type = type(self)
-
- if isinstance(self.args.get('value'), our_type):
- raise Exception("'value' must be a regular string; not an Lstr")
-
- if 'subs' in self.args:
- subs_new = []
- for key, value in keywds['subs']:
- if isinstance(value, our_type):
- subs_new.append((key, value.args))
- else:
- subs_new.append((key, value))
- self.args['subs'] = subs_new
-
- # As of protocol 31 we support compact key names
- # ('t' instead of 'translate', etc). Convert as needed.
- if 'translate' in keywds:
- keywds['t'] = keywds['translate']
- del keywds['translate']
- if 'resource' in keywds:
- keywds['r'] = keywds['resource']
- del keywds['resource']
- if 'value' in keywds:
- keywds['v'] = keywds['value']
- del keywds['value']
- if 'fallback' in keywds:
- from ba import _error
- _error.print_error(
- 'deprecated "fallback" arg passed to Lstr(); use '
- 'either "fallback_resource" or "fallback_value"',
- once=True)
- keywds['f'] = keywds['fallback']
- del keywds['fallback']
- if 'fallback_resource' in keywds:
- keywds['f'] = keywds['fallback_resource']
- del keywds['fallback_resource']
- if 'subs' in keywds:
- keywds['s'] = keywds['subs']
- del keywds['subs']
- if 'fallback_value' in keywds:
- keywds['fv'] = keywds['fallback_value']
- del keywds['fallback_value']
-
- def evaluate(self) -> str:
- """Evaluate the Lstr and returns a flat string in the current language.
-
- You should avoid doing this as much as possible and instead pass
- and store Lstr values.
- """
- return _ba.evaluate_lstr(self._get_json())
-
- def is_flat_value(self) -> bool:
- """Return whether the Lstr is a 'flat' value.
-
- This is defined as a simple string value incorporating no translations,
- resources, or substitutions. In this case it may be reasonable to
- replace it with a raw string value, perform string manipulation on it,
- etc.
- """
- return bool('v' in self.args and not self.args.get('s', []))
-
- def _get_json(self) -> str:
- try:
- return json.dumps(self.args, separators=(',', ':'))
- except Exception:
- from ba import _error
- _error.print_exception('_get_json failed for', self.args)
- return 'JSON_ERR'
-
- def __str__(self) -> str:
- return ''
-
- def __repr__(self) -> str:
- return ''
-
-
-def setlanguage(language: Optional[str],
- print_change: bool = True,
- store_to_config: bool = True) -> None:
- """Set the active language used for the game.
-
- category: General Utility Functions
-
- Pass None to use OS default language.
- """
- # pylint: disable=too-many-locals
- # pylint: disable=too-many-branches
- cfg = _ba.app.config
- cur_language = cfg.get('Lang', None)
-
- # Store this in the config if its changing.
- if language != cur_language and store_to_config:
- if language is None:
- if 'Lang' in cfg:
- del cfg['Lang'] # Clear it out for default.
- else:
- cfg['Lang'] = language
- cfg.commit()
- switched = True
- else:
- switched = False
-
- with open('ba_data/data/languages/english.json') as infile:
- lenglishvalues = json.loads(infile.read())
-
- # None implies default.
- if language is None:
- language = _ba.app.default_language
- try:
- if language == 'English':
- lmodvalues = None
- else:
- lmodfile = 'ba_data/data/languages/' + language.lower() + '.json'
- with open(lmodfile) as infile:
- lmodvalues = json.loads(infile.read())
- except Exception:
- from ba import _error
- _error.print_exception('Exception importing language:', language)
- _ba.screenmessage("Error setting language to '" + language +
- "'; see log for details",
- color=(1, 0, 0))
- switched = False
- lmodvalues = None
-
- # Create an attrdict of *just* our target language.
- _ba.app.language_target = AttrDict()
- langtarget = _ba.app.language_target
- assert langtarget is not None
- _add_to_attr_dict(langtarget,
- lmodvalues if lmodvalues is not None else lenglishvalues)
-
- # Create an attrdict of our target language overlaid on our base (english).
- languages = [lenglishvalues]
- if lmodvalues is not None:
- languages.append(lmodvalues)
- lfull = AttrDict()
- for lmod in languages:
- _add_to_attr_dict(lfull, lmod)
- _ba.app.language_merged = lfull
-
- # Pass some keys/values in for low level code to use;
- # start with everything in their 'internal' section.
- internal_vals = [
- v for v in list(lfull['internal'].items()) if isinstance(v[1], str)
- ]
-
- # Cherry-pick various other values to include.
- # (should probably get rid of the 'internal' section
- # and do everything this way)
- for value in [
- 'replayNameDefaultText', 'replayWriteErrorText',
- 'replayVersionErrorText', 'replayReadErrorText'
- ]:
- internal_vals.append((value, lfull[value]))
- internal_vals.append(
- ('axisText', lfull['configGamepadWindow']['axisText']))
- lmerged = _ba.app.language_merged
- assert lmerged is not None
- random_names = [
- n.strip() for n in lmerged['randomPlayerNamesText'].split(',')
- ]
- random_names = [n for n in random_names if n != '']
- _ba.set_internal_language_keys(internal_vals, random_names)
- if switched and print_change:
- _ba.screenmessage(Lstr(resource='languageSetText',
- subs=[('${LANGUAGE}',
- Lstr(translate=('languages', language)))
- ]),
- color=(0, 1, 0))
-
-
-def _add_to_attr_dict(dst: AttrDict, src: Dict) -> None:
- for key, value in list(src.items()):
- if isinstance(value, dict):
- try:
- dst_dict = dst[key]
- 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")
- _add_to_attr_dict(dst_dict, value)
- else:
- if not isinstance(value, (float, int, bool, str, str, type(None))):
- raise Exception("invalid value type for res '" + key + "': " +
- str(type(value)))
- dst[key] = value
-
-
-class AttrDict(dict):
- """A dict that can be accessed with dot notation.
-
- (so foo.bar is equivalent to foo['bar'])
- """
-
- def __getattr__(self, attr: str) -> Any:
- val = self[attr]
- assert not isinstance(val, bytes)
- return val
-
- def __setattr__(self, attr: str, value: Any) -> None:
- raise Exception()
-
-
-def get_resource(resource: str,
- fallback_resource: str = None,
- fallback_value: Any = None) -> Any:
- """Return a translation resource by name."""
- try:
- # If we have no language set, go ahead and set it.
- if _ba.app.language_merged is None:
- language = _ba.app.language
- try:
- setlanguage(language,
- print_change=False,
- store_to_config=False)
- except Exception:
- from ba import _error
- _error.print_exception('exception setting language to',
- language)
-
- # Try english as a fallback.
- if language != 'English':
- print('Resorting to fallback language (English)')
- try:
- setlanguage('English',
- print_change=False,
- store_to_config=False)
- except Exception:
- _error.print_exception(
- 'error setting language to english fallback')
-
- # If they provided a fallback_resource value, try the
- # target-language-only dict first and then fall back to trying the
- # fallback_resource value in the merged dict.
- if fallback_resource is not None:
- try:
- values = _ba.app.language_target
- splits = resource.split('.')
- dicts = splits[:-1]
- key = splits[-1]
- for dct in dicts:
- assert values is not None
- values = values[dct]
- assert values is not None
- val = values[key]
- return val
- except Exception:
- # FIXME: Shouldn't we try the fallback resource in the merged
- # dict AFTER we try the main resource in the merged dict?
- try:
- values = _ba.app.language_merged
- splits = fallback_resource.split('.')
- dicts = splits[:-1]
- key = splits[-1]
- for dct in dicts:
- assert values is not None
- values = values[dct]
- assert values is not None
- val = values[key]
- return val
-
- except Exception:
- # If we got nothing for fallback_resource, default to the
- # normal code which checks or primary value in the merge
- # dict; there's a chance we can get an english value for
- # it (which we weren't looking for the first time through).
- pass
-
- values = _ba.app.language_merged
- splits = resource.split('.')
- dicts = splits[:-1]
- key = splits[-1]
- for dct in dicts:
- assert values is not None
- values = values[dct]
- assert values is not None
- val = values[key]
- return val
-
- except Exception:
- # Ok, looks like we couldn't find our main or fallback resource
- # anywhere. Now if we've been given a fallback value, return it;
- # otherwise fail.
- if fallback_value is not None:
- return fallback_value
- raise Exception("resource not found: '" + resource + "'")
-
-
-def translate(category: str,
- strval: str,
- raise_exceptions: bool = False,
- print_errors: bool = False) -> str:
- """Translate a value (or return the value if no translation available)
-
- Generally you should use ba.Lstr which handles dynamic translation,
- as opposed to this which returns a flat string.
- """
- try:
- translated = get_resource('translations')[category][strval]
- except Exception as exc:
- if raise_exceptions:
- raise
- if print_errors:
- print(('Translate error: category=\'' + category + '\' name=\'' +
- strval + '\' exc=' + str(exc) + ''))
- translated = None
- translated_out: str
- if translated is None:
- translated_out = strval
- else:
- translated_out = translated
- assert isinstance(translated_out, str)
- return translated_out
-
-
-def get_valid_languages() -> List[str]:
- """Return a list containing names of all available languages.
-
- category: General Utility Functions
-
- Languages that may be present but are not displayable on the running
- version of the game are ignored.
- """
- langs = set()
- app = _ba.app
- try:
- names = os.listdir('ba_data/data/languages')
- names = [n.replace('.json', '').capitalize() for n in names]
-
- # FIXME: our simple capitalization fails on multi-word names;
- # should handle this in a better way...
- for i, name in enumerate(names):
- if name == 'Chinesetraditional':
- names[i] = 'ChineseTraditional'
- except Exception:
- from ba import _error
- _error.print_exception()
- names = []
- for name in names:
- if app.can_display_language(name):
- langs.add(name)
- return sorted(name for name in names if app.can_display_language(name))
-
-
-def is_custom_unicode_char(char: str) -> bool:
- """Return whether a char is in the custom unicode range we use."""
- assert isinstance(char, str)
- if len(char) != 1:
- raise Exception('Invalid Input; must be length 1')
- return 0xE000 <= ord(char) <= 0xF8FF
diff --git a/assets/src/ba_data/python/ba/_language.py b/assets/src/ba_data/python/ba/_language.py
new file mode 100644
index 00000000..98f0da56
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_language.py
@@ -0,0 +1,562 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Language related functionality."""
+from __future__ import annotations
+
+import json
+import os
+from typing import TYPE_CHECKING, overload
+
+import _ba
+
+if TYPE_CHECKING:
+ import ba
+ from typing import Any, Dict, List, Optional, Tuple, Union, Sequence
+
+
+class LanguageSubsystem:
+ """Wraps up language related app functionality.
+
+ Category: App Classes
+
+ To use this class, access the single instance of it at 'ba.app.lang'.
+ """
+
+ def __init__(self) -> None:
+ self.language_target: Optional[AttrDict] = None
+ self.language_merged: Optional[AttrDict] = None
+ self.default_language = self._get_default_language()
+
+ def _can_display_language(self, language: str) -> bool:
+ """Tell whether we can display a particular language.
+
+ On some platforms we don't have unicode rendering yet
+ which limits the languages we can draw.
+ """
+
+ # We don't yet support full unicode display on windows or linux :-(.
+ if (language in {
+ 'Chinese', 'ChineseTraditional', 'Persian', 'Korean', 'Arabic',
+ 'Hindi', 'Vietnamese'
+ } and not _ba.can_display_full_unicode()):
+ return False
+ return True
+
+ @property
+ def locale(self) -> str:
+ """Raw country/language code detected by the game (such as 'en_US').
+
+ Generally for language-specific code you should look at
+ ba.App.language, which is the language the game is using
+ (which may differ from locale if the user sets a language, etc.)
+ """
+ env = _ba.env()
+ assert isinstance(env['locale'], str)
+ return env['locale']
+
+ def _get_default_language(self) -> str:
+ languages = {
+ 'de': 'German',
+ 'es': 'Spanish',
+ 'sk': 'Slovak',
+ 'it': 'Italian',
+ 'nl': 'Dutch',
+ 'da': 'Danish',
+ 'pt': 'Portuguese',
+ 'fr': 'French',
+ 'el': 'Greek',
+ 'ru': 'Russian',
+ 'pl': 'Polish',
+ 'sv': 'Swedish',
+ 'eo': 'Esperanto',
+ 'cs': 'Czech',
+ 'hr': 'Croatian',
+ 'hu': 'Hungarian',
+ 'be': 'Belarussian',
+ 'ro': 'Romanian',
+ 'ko': 'Korean',
+ 'fa': 'Persian',
+ 'ar': 'Arabic',
+ 'zh': 'Chinese',
+ 'tr': 'Turkish',
+ 'id': 'Indonesian',
+ 'sr': 'Serbian',
+ 'uk': 'Ukrainian',
+ 'vi': 'Vietnamese',
+ 'vec': 'Venetian',
+ 'hi': 'Hindi'
+ }
+
+ # 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'
+ else:
+ language = languages.get(self.locale[:2], 'English')
+ if not self._can_display_language(language):
+ language = 'English'
+ return language
+
+ @property
+ def language(self) -> str:
+ """The name of the language the game is running in.
+
+ This can be selected explicitly by the user or may be set
+ automatically based on ba.App.locale or other factors.
+ """
+ assert isinstance(_ba.app.config, dict)
+ return _ba.app.config.get('Lang', self.default_language)
+
+ @property
+ def available_languages(self) -> List[str]:
+ """A list of all available languages.
+
+ Note that languages that may be present in game assets but which
+ are not displayable on the running version of the game are not
+ included here.
+ """
+ langs = set()
+ try:
+ names = os.listdir('ba_data/data/languages')
+ names = [n.replace('.json', '').capitalize() for n in names]
+
+ # FIXME: our simple capitalization fails on multi-word names;
+ # should handle this in a better way...
+ for i, name in enumerate(names):
+ if name == 'Chinesetraditional':
+ names[i] = 'ChineseTraditional'
+ except Exception:
+ from ba import _error
+ _error.print_exception()
+ names = []
+ for name in names:
+ if self._can_display_language(name):
+ langs.add(name)
+ return sorted(name for name in names
+ if self._can_display_language(name))
+
+ def setlanguage(self,
+ language: Optional[str],
+ print_change: bool = True,
+ store_to_config: bool = True) -> None:
+ """Set the active language used for the game.
+
+ 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)
+
+ # Store this in the config if its changing.
+ if language != cur_language and store_to_config:
+ if language is None:
+ if 'Lang' in cfg:
+ del cfg['Lang'] # Clear it out for default.
+ else:
+ cfg['Lang'] = language
+ cfg.commit()
+ switched = True
+ else:
+ switched = False
+
+ with open('ba_data/data/languages/english.json') as infile:
+ lenglishvalues = json.loads(infile.read())
+
+ # None implies default.
+ if language is None:
+ language = self.default_language
+ try:
+ if language == 'English':
+ lmodvalues = None
+ else:
+ lmodfile = 'ba_data/data/languages/' + language.lower(
+ ) + '.json'
+ with open(lmodfile) as infile:
+ lmodvalues = json.loads(infile.read())
+ except Exception:
+ from ba import _error
+ _error.print_exception('Exception importing language:', language)
+ _ba.screenmessage("Error setting language to '" + language +
+ "'; see log for details",
+ color=(1, 0, 0))
+ switched = False
+ lmodvalues = None
+
+ # Create an attrdict of *just* our target language.
+ self.language_target = AttrDict()
+ langtarget = self.language_target
+ assert langtarget is not None
+ _add_to_attr_dict(
+ langtarget,
+ lmodvalues if lmodvalues is not None else lenglishvalues)
+
+ # Create an attrdict of our target language overlaid
+ # on our base (english).
+ languages = [lenglishvalues]
+ if lmodvalues is not None:
+ languages.append(lmodvalues)
+ lfull = AttrDict()
+ for lmod in languages:
+ _add_to_attr_dict(lfull, lmod)
+ self.language_merged = lfull
+
+ # Pass some keys/values in for low level code to use;
+ # start with everything in their 'internal' section.
+ internal_vals = [
+ v for v in list(lfull['internal'].items())
+ if isinstance(v[1], str)
+ ]
+
+ # Cherry-pick various other values to include.
+ # (should probably get rid of the 'internal' section
+ # and do everything this way)
+ for value in [
+ 'replayNameDefaultText', 'replayWriteErrorText',
+ 'replayVersionErrorText', 'replayReadErrorText'
+ ]:
+ internal_vals.append((value, lfull[value]))
+ internal_vals.append(
+ ('axisText', lfull['configGamepadWindow']['axisText']))
+ internal_vals.append(('buttonText', lfull['buttonText']))
+ lmerged = self.language_merged
+ assert lmerged is not None
+ random_names = [
+ n.strip() for n in lmerged['randomPlayerNamesText'].split(',')
+ ]
+ random_names = [n for n in random_names if n != '']
+ _ba.set_internal_language_keys(internal_vals, random_names)
+ if switched and print_change:
+ _ba.screenmessage(Lstr(resource='languageSetText',
+ subs=[('${LANGUAGE}',
+ Lstr(translate=('languages',
+ language)))]),
+ color=(0, 1, 0))
+
+ def get_resource(self,
+ resource: str,
+ fallback_resource: str = None,
+ fallback_value: Any = None) -> Any:
+ """Return a translation resource by name.
+
+ DEPRECATED; use ba.Lstr functionality for these purposes.
+ """
+ try:
+ # If we have no language set, go ahead and set it.
+ if self.language_merged is None:
+ language = self.language
+ try:
+ self.setlanguage(language,
+ print_change=False,
+ store_to_config=False)
+ except Exception:
+ from ba import _error
+ _error.print_exception('exception setting language to',
+ language)
+
+ # Try english as a fallback.
+ if language != 'English':
+ print('Resorting to fallback language (English)')
+ try:
+ self.setlanguage('English',
+ print_change=False,
+ store_to_config=False)
+ except Exception:
+ _error.print_exception(
+ 'error setting language to english fallback')
+
+ # If they provided a fallback_resource value, try the
+ # target-language-only dict first and then fall back to trying the
+ # fallback_resource value in the merged dict.
+ if fallback_resource is not None:
+ try:
+ values = self.language_target
+ splits = resource.split('.')
+ dicts = splits[:-1]
+ key = splits[-1]
+ for dct in dicts:
+ assert values is not None
+ values = values[dct]
+ assert values is not None
+ val = values[key]
+ return val
+ except Exception:
+ # FIXME: Shouldn't we try the fallback resource in the
+ # merged dict AFTER we try the main resource in the
+ # merged dict?
+ try:
+ values = self.language_merged
+ splits = fallback_resource.split('.')
+ dicts = splits[:-1]
+ key = splits[-1]
+ for dct in dicts:
+ assert values is not None
+ values = values[dct]
+ assert values is not None
+ val = values[key]
+ return val
+
+ except Exception:
+ # If we got nothing for fallback_resource, default
+ # to the normal code which checks or primary
+ # value in the merge dict; there's a chance we can
+ # get an english value for it (which we weren't
+ # looking for the first time through).
+ pass
+
+ values = self.language_merged
+ splits = resource.split('.')
+ dicts = splits[:-1]
+ key = splits[-1]
+ for dct in dicts:
+ assert values is not None
+ values = values[dct]
+ assert values is not None
+ val = values[key]
+ return val
+
+ except Exception:
+ # Ok, looks like we couldn't find our main or fallback resource
+ # anywhere. Now if we've been given a fallback value, return it;
+ # otherwise fail.
+ from ba import _error
+ if fallback_value is not None:
+ return fallback_value
+ raise _error.NotFoundError(
+ f"Resource not found: '{resource}'") from None
+
+ def translate(self,
+ category: str,
+ strval: str,
+ raise_exceptions: bool = False,
+ print_errors: bool = False) -> str:
+ """Translate a value (or return the value if no translation available)
+
+ DEPRECATED; use ba.Lstr functionality for these purposes.
+ """
+ try:
+ translated = self.get_resource('translations')[category][strval]
+ except Exception as exc:
+ if raise_exceptions:
+ raise
+ if print_errors:
+ print(('Translate error: category=\'' + category +
+ '\' name=\'' + strval + '\' exc=' + str(exc) + ''))
+ translated = None
+ translated_out: str
+ if translated is None:
+ translated_out = strval
+ else:
+ translated_out = translated
+ assert isinstance(translated_out, str)
+ return translated_out
+
+ def is_custom_unicode_char(self, char: str) -> bool:
+ """Return whether a char is in the custom unicode range we use."""
+ assert isinstance(char, str)
+ if len(char) != 1:
+ raise ValueError('Invalid Input; must be length 1')
+ return 0xE000 <= ord(char) <= 0xF8FF
+
+
+class Lstr:
+ """Used to define strings in a language-independent way.
+
+ category: General Utility Classes
+
+ These should be used whenever possible in place of hard-coded strings
+ so that in-game or UI elements show up correctly on all clients in their
+ currently-active language.
+
+ To see available resource keys, look at any of the bs_language_*.py files
+ in the game or the translations pages at bombsquadgame.com/translate.
+
+ # EXAMPLE 1: specify a string from a resource path
+ mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText')
+
+ # EXAMPLE 2: specify a translated string via a category and english value;
+ # if a translated value is available, it will be used; otherwise the
+ # english value will be. To see available translation categories, look
+ # under the 'translations' resource section.
+ mynode.text = ba.Lstr(translate=('gameDescriptions', 'Defeat all enemies'))
+
+ # EXAMPLE 3: specify a raw value and some substitutions. Substitutions can
+ # be used with resource and translate modes as well.
+ mynode.text = ba.Lstr(value='${A} / ${B}',
+ subs=[('${A}', str(score)), ('${B}', str(total))])
+
+ # EXAMPLE 4: Lstrs can be nested. This example would display the resource
+ # at res_a but replace ${NAME} with the value of the resource at res_b
+ mytextnode.text = ba.Lstr(resource='res_a',
+ subs=[('${NAME}', ba.Lstr(resource='res_b'))])
+ """
+
+ # pylint: disable=dangerous-default-value
+ # noinspection PyDefaultArgument
+ @overload
+ def __init__(self,
+ *,
+ resource: str,
+ fallback_resource: str = '',
+ fallback_value: str = '',
+ subs: Sequence[Tuple[str, Union[str, Lstr]]] = []) -> None:
+ """Create an Lstr from a string resource."""
+ ...
+
+ # noinspection PyShadowingNames,PyDefaultArgument
+ @overload
+ def __init__(self,
+ *,
+ translate: Tuple[str, str],
+ subs: Sequence[Tuple[str, Union[str, Lstr]]] = []) -> None:
+ """Create an Lstr by translating a string in a category."""
+ ...
+
+ # noinspection PyDefaultArgument
+ @overload
+ def __init__(self,
+ *,
+ value: str,
+ subs: Sequence[Tuple[str, Union[str, Lstr]]] = []) -> None:
+ """Create an Lstr from a raw string value."""
+ ...
+
+ # pylint: enable=redefined-outer-name, dangerous-default-value
+
+ def __init__(self, *args: Any, **keywds: Any) -> None:
+ """Instantiate a Lstr.
+
+ Pass a value for either 'resource', 'translate',
+ or 'value'. (see Lstr help for examples).
+ 'subs' can be a sequence of 2-member sequences consisting of values
+ and replacements.
+ 'fallback_resource' can be a resource key that will be used if the
+ main one is not present for
+ the current language in place of falling back to the english value
+ ('resource' mode only).
+ 'fallback_value' can be a literal string that will be used if neither
+ the resource nor the fallback resource is found ('resource' mode only).
+ """
+ # pylint: disable=too-many-branches
+ if args:
+ raise TypeError('Lstr accepts only keyword arguments')
+
+ # Basically just store the exact args they passed.
+ # However if they passed any Lstr values for subs,
+ # replace them with that Lstr's dict.
+ self.args = keywds
+ our_type = type(self)
+
+ if isinstance(self.args.get('value'), our_type):
+ raise TypeError("'value' must be a regular string; not an Lstr")
+
+ if 'subs' in self.args:
+ subs_new = []
+ for key, value in keywds['subs']:
+ if isinstance(value, our_type):
+ subs_new.append((key, value.args))
+ else:
+ subs_new.append((key, value))
+ self.args['subs'] = subs_new
+
+ # As of protocol 31 we support compact key names
+ # ('t' instead of 'translate', etc). Convert as needed.
+ if 'translate' in keywds:
+ keywds['t'] = keywds['translate']
+ del keywds['translate']
+ if 'resource' in keywds:
+ keywds['r'] = keywds['resource']
+ del keywds['resource']
+ if 'value' in keywds:
+ keywds['v'] = keywds['value']
+ del keywds['value']
+ if 'fallback' in keywds:
+ from ba import _error
+ _error.print_error(
+ 'deprecated "fallback" arg passed to Lstr(); use '
+ 'either "fallback_resource" or "fallback_value"',
+ once=True)
+ keywds['f'] = keywds['fallback']
+ del keywds['fallback']
+ if 'fallback_resource' in keywds:
+ keywds['f'] = keywds['fallback_resource']
+ del keywds['fallback_resource']
+ if 'subs' in keywds:
+ keywds['s'] = keywds['subs']
+ del keywds['subs']
+ if 'fallback_value' in keywds:
+ keywds['fv'] = keywds['fallback_value']
+ del keywds['fallback_value']
+
+ def evaluate(self) -> str:
+ """Evaluate the Lstr and returns a flat string in the current language.
+
+ You should avoid doing this as much as possible and instead pass
+ and store Lstr values.
+ """
+ return _ba.evaluate_lstr(self._get_json())
+
+ def is_flat_value(self) -> bool:
+ """Return whether the Lstr is a 'flat' value.
+
+ This is defined as a simple string value incorporating no translations,
+ resources, or substitutions. In this case it may be reasonable to
+ replace it with a raw string value, perform string manipulation on it,
+ etc.
+ """
+ return bool('v' in self.args and not self.args.get('s', []))
+
+ def _get_json(self) -> str:
+ try:
+ return json.dumps(self.args, separators=(',', ':'))
+ except Exception:
+ from ba import _error
+ _error.print_exception('_get_json failed for', self.args)
+ return 'JSON_ERR'
+
+ def __str__(self) -> str:
+ return ''
+
+ 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 _add_to_attr_dict(dst: AttrDict, src: Dict) -> None:
+ for key, value in list(src.items()):
+ if isinstance(value, dict):
+ try:
+ dst_dict = dst[key]
+ except Exception:
+ dst_dict = dst[key] = AttrDict()
+ if not isinstance(dst_dict, AttrDict):
+ 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))):
+ raise TypeError("invalid value type for res '" + key + "': " +
+ str(type(value)))
+ dst[key] = value
+
+
+class AttrDict(dict):
+ """A dict that can be accessed with dot notation.
+
+ (so foo.bar is equivalent to foo['bar'])
+ """
+
+ def __getattr__(self, attr: str) -> Any:
+ val = self[attr]
+ assert not isinstance(val, bytes)
+ return val
+
+ def __setattr__(self, attr: str, value: Any) -> None:
+ raise Exception()
diff --git a/assets/src/ba_data/python/ba/_level.py b/assets/src/ba_data/python/ba/_level.py
index 44f805fa..c45f7156 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
@@ -42,10 +24,9 @@ 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."""
self._name = name
self._gametype = gametype
self._settings = settings
@@ -81,8 +62,8 @@ class Level:
@property
def displayname(self) -> ba.Lstr:
"""The localized name for this Level."""
- from ba import _lang
- return _lang.Lstr(
+ from ba import _language
+ return _language.Lstr(
translate=('coopLevelNames', self._displayname
if self._displayname is not None else self._name),
subs=[('${GAME}',
@@ -93,8 +74,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 +105,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()
@@ -144,8 +126,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.getscoreconfig().version
if scorever != '':
scorever = ' ' + scorever
self._score_version_string = scorever
@@ -168,15 +149,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 Exception('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/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py
index e755849f..577a0c42 100644
--- a/assets/src/ba_data/python/ba/_lobby.py
+++ b/assets/src/ba_data/python/ba/_lobby.py
@@ -1,84 +1,50 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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."""
-# 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._language import Lstr
+from ba._enums import SpecialChar, InputType
+from ba._profile import get_player_profile_colors
if TYPE_CHECKING:
from typing import Optional, List, Dict, Any, Sequence, Union
import ba
+MAX_QUICK_CHANGE_COUNT = 30
+QUICK_CHANGE_INTERVAL = 0.05
+QUICK_CHANGE_RESET_INTERVAL = 1.0
+
# Hmm should we move this to actors?..
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.sessionteams) > 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(
@@ -90,11 +56,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]
+ if _ba.app.demo_mode or _ba.app.arcade_mode:
+ self._messages = [self._joinmsg]
else:
msg1 = Lstr(resource='pressToSelectProfileText',
subs=[
@@ -104,15 +70,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]
@@ -144,15 +133,8 @@ class Chooser:
if self._text_node:
self._text_node.delete()
- def __init__(self, vpos: float, player: _ba.Player,
+ def __init__(self, vpos: float, sessionplayer: _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')
@@ -161,129 +143,47 @@ 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
self._profilename = ''
self._profilenames: List[str] = []
self._ready: bool = False
- self.character_names: List[str] = []
+ 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
- # 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*
# 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 = (
+ (sessionplayer.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={
@@ -295,8 +195,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={
@@ -306,25 +205,88 @@ class Chooser:
'attach': 'topCenter'
})
- _gameutils.animate_array(self.icon, 'scale', 2, {
- 0: (0, 0),
- 0.1: (45, 45)
- })
-
- self._set_ready(False)
+ 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(
- _lang.Lstr(resource='choosingPlayerText').evaluate(), real=False)
+ self._sessionplayer.setname(
+ Lstr(resource='choosingPlayerText').evaluate(), real=False)
- self.update_from_player_profiles()
+ # 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)
+
+ def _select_initial_profile(self) -> int:
+ app = _ba.app
+ profilenames = self._profilenames
+ inputdevice = self._sessionplayer.inputdevice
+
+ # 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.Player:
- """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:
@@ -339,52 +301,49 @@ class Chooser:
"""(internal)"""
self._dead = val
- def get_team(self) -> ba.Team:
- """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:
"""The chooser's ba.Lobby."""
lobby = self._lobby()
if lobby is None:
- raise Exception('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()
@@ -395,52 +354,52 @@ 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._sessionplayer.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 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:
- self.profiles['_edit'] = {}
+ 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.
- 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:
@@ -451,90 +410,67 @@ 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) +
+ 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
- _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
+ def _getname(self, full: bool = False) -> str:
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._sessionplayer.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._sessionplayer.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
@@ -555,43 +491,47 @@ 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._sessionplayer.inputdevice)
return
if not ready:
- self._player.assign_input_call(
- 'leftPress', Call(self.handlemessage,
- ChangeMessage('team', -1)))
- self._player.assign_input_call(
- 'rightPress', Call(self.handlemessage,
- ChangeMessage('team', 1)))
- self._player.assign_input_call(
- 'bombPress',
+ self._sessionplayer.assigninput(
+ InputType.LEFT_PRESS,
+ Call(self.handlemessage, ChangeMessage('team', -1)))
+ self._sessionplayer.assigninput(
+ InputType.RIGHT_PRESS,
+ Call(self.handlemessage, ChangeMessage('team', 1)))
+ self._sessionplayer.assigninput(
+ InputType.BOMB_PRESS,
Call(self.handlemessage, ChangeMessage('character', 1)))
- self._player.assign_input_call(
- 'upPress',
+ self._sessionplayer.assigninput(
+ InputType.UP_PRESS,
Call(self.handlemessage, ChangeMessage('profileindex', -1)))
- self._player.assign_input_call(
- 'downPress',
+ self._sessionplayer.assigninput(
+ InputType.DOWN_PRESS,
Call(self.handlemessage, ChangeMessage('profileindex', 1)))
- self._player.assign_input_call(
- ('jumpPress', 'pickUpPress', 'punchPress'),
+ self._sessionplayer.assigninput(
+ (InputType.JUMP_PRESS, InputType.PICK_UP_PRESS,
+ InputType.PUNCH_PRESS),
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(
- ('leftPress', 'rightPress', 'upPress', 'downPress',
- 'jumpPress', 'bombPress', 'pickUpPress'), self._do_nothing)
- self._player.assign_input_call(
- ('jumpPress', 'bombPress', 'pickUpPress', 'punchPress'),
+ self._sessionplayer.assigninput(
+ (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(
+ (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.
- input_device = self._player.get_input_device()
+ input_device = self._sessionplayer.inputdevice
name = input_device.name
unique_id = input_device.unique_identifier
device_profiles = _ba.app.config.setdefault(
@@ -601,7 +541,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:
@@ -612,9 +553,9 @@ 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),
- real=True)
+ self._sessionplayer.setname(self._getname(),
+ self._getname(full=True),
+ real=True)
self._ready = True
self._update_text()
@@ -629,26 +570,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.get_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().get_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().get_id()] >=
+ and team_player_counts[self.sessionteam.id] >=
largest_team_size):
force_team_switch = True
@@ -660,27 +601,41 @@ class Chooser:
_ba.playsound(self._punchsound)
self._set_ready(ready)
+ # 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._sessionplayer.inputdevice.client_id)
+ 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:
- 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':
- 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()
@@ -698,13 +653,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()
@@ -712,26 +667,24 @@ 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:
# 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._sessionplayer.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
+ can_switch_teams = len(self.lobby.sessionteams) > 1
# 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
@@ -740,7 +693,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
})
@@ -752,10 +705,8 @@ 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
+ val = self.lobby.sessionteams[self._selected_team_index].color
else:
val = self._color
if len(val) != 3:
@@ -772,17 +723,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],
@@ -794,12 +745,11 @@ 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
+ return self._sessionplayer
def _update_icon(self) -> None:
- from ba import _gameutils
if self._profilenames[self._profileindex] == '_edit':
tex = _ba.gettexture('black')
tint_tex = _ba.gettexture('black')
@@ -810,13 +760,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'
@@ -829,11 +778,11 @@ 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:
- _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)
@@ -841,7 +790,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
})
@@ -850,7 +799,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:
@@ -861,27 +810,27 @@ 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 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._sessionteams = [
+ weakref.ref(team) for team in session.sessionteams
+ ]
else:
- self._dummy_teams = bs_team.Team()
- self._teams = [weakref.ref(self._dummy_teams)]
- v_offset = (-150
- if isinstance(session, _coopsession.CoopSession) else -50)
+ self._dummy_teams = SessionTeam()
+ 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
self.update_positions()
@@ -908,10 +857,10 @@ class Lobby:
return self._use_team_colors
@property
- def teams(self) -> List[ba.Team]:
- """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)
@@ -932,7 +881,6 @@ class Lobby:
def reload_profiles(self) -> None:
"""Reload available player profiles."""
# pylint: disable=cyclic-import
- from ba._account import ensure_have_account_player_profile
from bastd.actor.spazappearance import get_appearances
# We may have gained or lost character names if the user
@@ -941,14 +889,13 @@ class Lobby:
self.character_names_local_unlocked.sort(key=lambda x: x.lower())
# Do any overall prep we need to such as creating account profile.
- ensure_have_account_player_profile()
+ _ba.app.accounts.ensure_have_account_player_profile()
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."""
@@ -962,15 +909,16 @@ 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, 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.Player) -> None:
- """Remove a single player's chooser; does not kick him.
+ def remove_chooser(self, player: ba.SessionPlayer) -> None:
+ """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."""
@@ -987,11 +935,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:
@@ -1007,6 +953,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/_map.py b/assets/src/ba_data/python/ba/_map.py
index d5e57e31..3bd4c55d 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
@@ -66,8 +48,8 @@ def get_map_display_string(name: str) -> ba.Lstr:
Category: Asset Functions
"""
- from ba import _lang
- return _lang.Lstr(translate=('mapsNames', name))
+ from ba import _language
+ return _language.Lstr(translate=('mapsNames', name))
def getmaps(playtype: str) -> List[str]:
@@ -126,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):
@@ -143,8 +125,9 @@ def get_map_class(name: str) -> Type[ba.Map]:
name = get_filtered_map_name(name)
try:
return _ba.app.maps[name]
- except Exception:
- raise Exception("Map not found: '" + name + "'")
+ except KeyError:
+ from ba import _error
+ raise _error.NotFoundError(f"Map not found: '{name}'") from None
class Map(Actor):
@@ -191,7 +174,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
@@ -217,25 +200,27 @@ class Map(Actor):
# (and instruct the user if we weren't preloaded properly).
try:
self.preloaddata = _ba.getactivity().preloads[type(self)]
- except Exception:
- raise Exception('Preload data not found for ' + str(type(self)) +
- '; make sure to call the type\'s preload()'
- ' staticmethod in the activity constructor')
+ 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') from exc
# 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')
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)
@@ -339,7 +324,7 @@ class Map(Actor):
point_list.append(pts)
else:
if len(pts) != 3:
- raise Exception('invalid point')
+ raise ValueError('invalid point')
point_list.append(pts + (0, 0, 0))
i += 1
return point_list
@@ -364,12 +349,8 @@ class Map(Actor):
# Get positions for existing players.
player_pts = []
for player in players:
- try:
- if player.node:
- pnt = _ba.Vec3(player.node.position)
- player_pts.append(pnt)
- except Exception as exc:
- print('EXC in get_ffa_start_position:', exc)
+ if player.is_alive():
+ player_pts.append(player.position)
def _getpt() -> Sequence[float]:
point = self.ffa_spawn_points[self._next_ffa_start_index]
@@ -427,5 +408,5 @@ class Map(Actor):
def register_map(maptype: Type[Map]) -> None:
"""Register a map class with the game."""
if maptype.name in _ba.app.maps:
- raise Exception('map "' + maptype.name + '" already registered')
+ raise RuntimeError('map "' + maptype.name + '" already registered')
_ba.app.maps[maptype.name] = maptype
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 9ac55859..c57ea556 100644
--- a/assets/src/ba_data/python/ba/_messages.py
+++ b/assets/src/ba_data/python/ba/_messages.py
@@ -1,38 +1,30 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
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
+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.
@@ -78,6 +70,64 @@ class DieMessage:
how: DeathType = DeathType.GENERIC
+PlayerType = TypeVar('PlayerType', bound='ba.Player')
+
+
+class PlayerDiedMessage:
+ """A message saying a ba.Player has died.
+
+ category: Message Classes
+
+ Attributes:
+
+ killed
+ If True, the player 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 ba.Player that died.
+
+ 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)
+
+ # 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.
@@ -202,7 +252,6 @@ class CelebrateMessage:
duration: float = 10.0
-@dataclass(init=False)
class HitMessage:
"""Tells an object it has been hit in some way.
@@ -233,7 +282,10 @@ class HitMessage:
self.magnitude = magnitude
self.velocity_magnitude = velocity_magnitude
self.radius = radius
- self.source_player = source_player
+
+ # 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
self.flat_damage = flat_damage
self.hit_type = hit_type
@@ -241,6 +293,19 @@ 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 source-player if one exists and is the provided type."""
+ player: Any = self._source_player
+
+ # We should not be delivering invalid refs.
+ # (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 the player *only* if they're the type given.
+ return player if isinstance(player, playertype) else None
+
@dataclass
class PlayerProfilesChangedMessage:
diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py
index 6aa52847..03865528 100644
--- a/assets/src/ba_data/python/ba/_meta.py
+++ b/assets/src/ba_data/python/ba/_meta.py
@@ -1,28 +1,11 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
import os
+import time
import pathlib
import threading
from typing import TYPE_CHECKING
@@ -37,7 +20,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
@@ -45,39 +28,161 @@ 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)
+ keyboards: List[str] = field(default_factory=list)
errors: str = ''
warnings: str = ''
-def start_scan() -> None:
- """Begin scanning script directories for scripts containing metadata.
+class MetadataSubsystem:
+ """Subsystem for working with script metadata in the app.
- Should be called only once at launch."""
- 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]
- thread = ScanThread(scriptdirs)
- thread.start()
+ Category: App Classes
+ Access the single shared instance of this class at 'ba.app.meta'.
+ """
-def handle_scan_results(results: ScanResults) -> None:
- """Called in the game thread with results of a completed scan."""
- from ba import _lang
+ def __init__(self) -> None:
+ self.metascan: Optional[ScanResults] = None
- # 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
- # warnings = results.get('warnings', '')
- # errors = results.get('errors', '')
- if results.warnings != '' or results.errors != '':
- _ba.screenmessage(_lang.Lstr(resource='scanScriptsErrorText'),
- color=(1, 0, 0))
- _ba.playsound(_ba.getsound('error'))
- if results.warnings != '':
- _ba.log(results.warnings, to_server=False)
- if results.errors != '':
- _ba.log(results.errors)
+ def on_app_launch(self) -> None:
+ """Should be called when the app is done bootstrapping."""
+
+ # Start scanning for things exposed via ba_meta.
+ self.start_scan()
+
+ def start_scan(self) -> None:
+ """Begin scanning script directories for scripts containing metadata.
+
+ Should be called only once at launch."""
+ app = _ba.app
+ if self.metascan is not None:
+ print('WARNING: meta scan run more than once.')
+ pythondirs = [app.python_directory_app, app.python_directory_user]
+ thread = ScanThread(pythondirs)
+ thread.start()
+
+ def handle_scan_results(self, results: ScanResults) -> None:
+ """Called in the game thread with results of a completed scan."""
+
+ from ba._language 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.)
+ # Errors are more serious and will get included in the regular log
+ # warnings = results.get('warnings', '')
+ # errors = results.get('errors', '')
+ if results.warnings != '' or results.errors != '':
+ import textwrap
+ _ba.screenmessage(Lstr(resource='scanScriptsErrorText'),
+ color=(1, 0, 0))
+ _ba.playsound(_ba.getsound('error'))
+ if results.warnings != '':
+ _ba.log(textwrap.indent(results.warnings,
+ 'Warning (meta-scan): '),
+ to_server=False)
+ if results.errors != '':
+ _ba.log(textwrap.indent(results.errors, 'Error (meta-scan): '))
+
+ # Handle plugins.
+ plugs = _ba.app.plugins
+ config_changed = False
+ found_new = False
+ plugstates: Dict[str, Dict] = _ba.app.config.setdefault('Plugins', {})
+ assert isinstance(plugstates, dict)
+
+ # Create a potential-plugin for each class we found in the scan.
+ for class_path in results.plugins:
+ plugs.potential_plugins.append(
+ PotentialPlugin(display_name=Lstr(value=class_path),
+ class_path=class_path,
+ available=True))
+ if class_path not in plugstates:
+ if _ba.app.headless_mode:
+ # If we running in headless mode, enable plugin by default
+ # to allow server admins to get their modified build
+ # working 'out-of-the-box', without manually updating the
+ # config.
+ plugstates[class_path] = {'enabled': True}
+ else:
+ # If we running in normal mode, disable plugin by default
+ # (user can enable it later).
+ 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:
+ plugs.potential_plugins.append(
+ PotentialPlugin(display_name=Lstr(value=class_path),
+ class_path=class_path,
+ available=False))
+
+ plugs.potential_plugins.sort(key=lambda p: p.class_path)
+
+ if found_new:
+ _ba.screenmessage(Lstr(resource='pluginsDetectedText'),
+ color=(0, 1, 0))
+ _ba.playsound(_ba.getsound('ding'))
+
+ if config_changed:
+ _ba.app.config.commit()
+
+ def get_scan_results(self) -> ScanResults:
+ """Return meta scan results; block if the scan is not yet complete."""
+ if self.metascan is None:
+ print('WARNING: ba.meta.get_scan_results()'
+ ' called before scan completed.'
+ ' This can cause hitches.')
+
+ # Now wait a bit for the scan to complete.
+ # Eventually error though if it doesn't.
+ starttime = time.time()
+ while self.metascan is None:
+ time.sleep(0.05)
+ if time.time() - starttime > 10.0:
+ raise TimeoutError(
+ 'timeout waiting for meta scan to complete.')
+ return self.metascan
+
+ def get_game_types(self) -> List[Type[ba.GameActivity]]:
+ """Return available game types."""
+ from ba._general import getclass
+ from ba._gameactivity import GameActivity
+ gameclassnames = self.get_scan_results().games
+ gameclasses = []
+ for gameclassname in gameclassnames:
+ try:
+ cls = getclass(gameclassname, GameActivity)
+ gameclasses.append(cls)
+ except Exception:
+ from ba import _error
+ _error.print_exception('error importing ' + str(gameclassname))
+ unowned = self.get_unowned_game_types()
+ return [cls for cls in gameclasses if cls not in unowned]
+
+ def get_unowned_game_types(self) -> Set[Type[ba.GameActivity]]:
+ """Return present game types not owned by the current account."""
+ try:
+ from ba import _store
+ unowned_games: Set[Type[ba.GameActivity]] = set()
+ 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):
+ m_info = _store.get_store_item(mname)
+ unowned_games.add(m_info['gametype'])
+ return unowned_games
+ except Exception:
+ from ba import _error
+ _error.print_exception('error calcing un-owned games')
+ return set()
class ScanThread(threading.Thread):
@@ -88,7 +193,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()
@@ -98,13 +203,13 @@ 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(_ba.app.meta.handle_scan_results, results),
from_other_thread=True)
# We also, however, immediately make results available.
# This is because the game thread may be blocked waiting
# for them so we can't push a call or we'd get deadlock.
- _ba.app.metascan = results
+ _ba.app.meta.metascan = results
class DirectoryScan:
@@ -115,16 +220,10 @@ 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
"""
- 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(
@@ -166,6 +265,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:
@@ -206,7 +308,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 += (
@@ -247,6 +350,10 @@ class DirectoryScan:
classname = modulename + '.' + export_class_name
if exporttype == 'game':
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) +
@@ -271,7 +378,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 +398,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])
@@ -309,57 +416,3 @@ class DirectoryScan:
': no valid "# ba_meta api require " line found;'
' ignoring module.\n')
return None
-
-
-def get_scan_results() -> ScanResults:
- """Return meta scan results; blocking if the scan is not yet complete."""
- import time
- app = _ba.app
- if app.metascan is None:
- print(
- 'WARNING: ba.meta.get_scan_results() called before scan completed.'
- ' This can cause hitches.')
-
- # Now wait a bit for the scan to complete.
- # Eventually error though if it doesn't.
- starttime = time.time()
- while app.metascan is None:
- time.sleep(0.05)
- if time.time() - starttime > 10.0:
- raise Exception('timeout waiting for meta scan to complete.')
- return app.metascan
-
-
-def get_game_types() -> List[Type[ba.GameActivity]]:
- """Return available game types."""
- from ba import _general
- from ba import _gameactivity
- gameclassnames = get_scan_results().games
- gameclasses = []
- for gameclassname in gameclassnames:
- try:
- cls = _general.getclass(gameclassname, _gameactivity.GameActivity)
- gameclasses.append(cls)
- except Exception:
- from ba import _error
- _error.print_exception('error importing ' + str(gameclassname))
- unowned = get_unowned_game_types()
- return [cls for cls in gameclasses if cls not in unowned]
-
-
-def get_unowned_game_types() -> Set[Type[ba.GameActivity]]:
- """Return present game types not owned by the current account."""
- try:
- from ba import _store
- unowned_games: Set[Type[ba.GameActivity]] = set()
- if not _ba.app.headless_build:
- for section in _store.get_store_layout()['minigames']:
- for mname in section['items']:
- if not _ba.get_purchased(mname):
- m_info = _store.get_store_item(mname)
- unowned_games.add(m_info['gametype'])
- return unowned_games
- except Exception:
- from ba import _error
- _error.print_exception('error calcing un-owned games')
- return set()
diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py
index e94815f2..910b72e1 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
@@ -27,6 +9,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
@@ -58,7 +41,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:
@@ -71,7 +54,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())
@@ -85,7 +67,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
@@ -106,7 +88,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()
@@ -133,7 +115,7 @@ class MultiTeamSession(Session):
self._instantiate_next_game()
# Start in our custom join screen.
- self.set_activity(_ba.new_activity(MultiTeamJoinActivity))
+ self.setactivity(_ba.newactivity(MultiTeamJoinActivity))
def get_ffa_series_length(self) -> int:
"""Return free-for-all series length."""
@@ -149,60 +131,58 @@ 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."""
return self._game_number
- def on_team_join(self, team: ba.Team) -> None:
- team.sessiondata['previous_score'] = team.sessiondata['score'] = 0
+ def on_team_join(self, team: ba.SessionTeam) -> None:
+ 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."""
- 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)
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'])
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)
- 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.
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(
- _ba.new_activity(_activitytypes.TransitionActivity))
+ self.setactivity(_ba.newactivity(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
+ for team in self.sessionteams:
+ team.customdata['score'] = 0
# Otherwise just set accum (per-game) scores.
else:
@@ -218,19 +198,19 @@ 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:
- has_team = (player.team is not None)
- except _error.TeamNotFoundError:
+ has_team = (player.sessionteam is not None)
+ except NotFoundError:
has_team = False
if has_team:
- self.stats.register_player(player)
- self.stats.set_activity(next_game)
+ self.stats.register_sessionplayer(player)
+ 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:
@@ -238,13 +218,12 @@ 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,
- results: ba.TeamGameResults,
+ results: ba.GameResults,
delay: float,
announce_winning_team: bool = True) -> None:
"""Show basic game result at the end of a game.
@@ -256,20 +235,21 @@ 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._language 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:
+ winning_sessionteam = results.winning_sessionteam
+ if winning_sessionteam is not None:
# Have all players celebrate.
celebrate_msg = CelebrateMessage(duration=10.0)
- for player in winning_team.players:
+ assert winning_sessionteam.activityteam is not None
+ for player in winning_sessionteam.activityteam.players:
if player.actor:
player.actor.handlemessage(celebrate_msg)
cameraflash()
@@ -279,12 +259,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_sessionteam.name)])
+ activity.show_zoom_message(
+ wins_text,
+ scale=0.85,
+ color=normalized_color(winning_sessionteam.color),
+ )
class ShuffleList:
diff --git a/assets/src/ba_data/python/ba/_music.py b/assets/src/ba_data/python/ba/_music.py
index c1bd2524..c2f92d99 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
@@ -30,6 +12,7 @@ import _ba
if TYPE_CHECKING:
from typing import Callable, Any, Optional, Dict, Union, Type
+ import ba
class MusicType(Enum):
@@ -134,10 +117,12 @@ 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
+
+ Access the single shared instance of this class at 'ba.app.music'.
"""
def __init__(self) -> None:
@@ -191,7 +176,7 @@ class MusicController:
"""Returns the system music player, instantiating if necessary."""
if self._music_player is None:
if self._music_player_type is None:
- raise Exception('no music player type set')
+ raise TypeError('no music player type set')
self._music_player = self._music_player_type()
return self._music_player
@@ -248,20 +233,21 @@ class MusicController:
and isinstance(entry['name'], str)):
entry_type = entry['type']
else:
- raise Exception('invalid soundtrack entry: ' + str(entry) +
+ raise TypeError('invalid soundtrack entry: ' + str(entry) +
' (type ' + str(type(entry)) + ')')
if self.supports_soundtrack_entry_type(entry_type):
return entry_type
- raise Exception('invalid soundtrack entry:' + str(entry))
- except Exception as exc:
- print('EXC on get_soundtrack_entry_type', exc)
+ raise ValueError('invalid soundtrack entry:' + str(entry))
+ except Exception:
+ from ba import _error
+ _error.print_exception()
return 'default'
def get_soundtrack_entry_name(self, entry: Any) -> str:
"""Given a soundtrack entry, returns its name."""
try:
if entry is None:
- raise Exception('entry is None')
+ raise TypeError('entry is None')
# Simple string denotes an iTunesPlaylist name (legacy entry).
if isinstance(entry, str):
@@ -272,7 +258,7 @@ class MusicController:
and isinstance(entry['type'], str) and 'name' in entry
and isinstance(entry['name'], str)):
return entry['name']
- raise Exception('invalid soundtrack entry:' + str(entry))
+ raise ValueError('invalid soundtrack entry:' + str(entry))
except Exception:
from ba import _error
_error.print_exception()
@@ -484,8 +470,9 @@ class MusicPlayer:
self._actually_playing = False
-def setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None:
- """Tell the game to play (or stop playing) a certain type of music.
+def setmusic(musictype: Optional[ba.MusicType],
+ continuous: bool = False) -> None:
+ """Set the app to play (or stop playing) a certain type of music.
category: Gameplay Functions
@@ -505,7 +492,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/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py
index 1f290972..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
@@ -56,7 +38,7 @@ def get_ip_address_type(addr: str) -> socket.AddressFamily:
except OSError:
pass
if socket_type is None:
- raise Exception('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
@@ -76,14 +58,14 @@ class ServerCallThread(threading.Thread):
self._request = request
self._request_type = request_type
if not isinstance(response_type, ServerResponseType):
- raise Exception(f'Invalid response type: {response_type}')
+ raise TypeError(f'Invalid response type: {response_type}')
self._response_type = response_type
self._data = {} if data is None else copy.deepcopy(data)
self._callback: Optional[ServerCallbackType] = callback
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
@@ -94,7 +76,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,
@@ -105,16 +87,15 @@ 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)
_ba.set_thread_name('BA_ServerCallThread')
-
- # Seems pycharm doesn't know about urllib.parse.
- # noinspection PyUnresolvedReferences
parse = urllib.parse
if self._request_type == 'get':
response = urllib.request.urlopen(
@@ -129,7 +110,7 @@ class ServerCallThread(threading.Thread):
parse.urlencode(self._data).encode(),
{'User-Agent': _ba.app.user_agent_string}))
else:
- raise Exception('Invalid request_type: ' + self._request_type)
+ raise TypeError('Invalid request_type: ' + self._request_type)
# If html request failed.
if response.getcode() != 200:
@@ -145,23 +126,49 @@ class ServerCallThread(threading.Thread):
raw_data_s = raw_data.decode()
response_data = json.loads(raw_data_s)
else:
- raise Exception(f'invalid responsetype: {self._response_type}')
- except (urllib.error.URLError, ConnectionError):
- # Server rejected us, broken pipe, etc. It happens. Ignoring.
- response_data = None
+ raise TypeError(f'invalid responsetype: {self._response_type}')
+
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, http.client.BadStatusLine)):
+ pass
+ elif isinstance(exc, OSError):
+ if exc.errno == 10051: # Windows unreachable network error.
+ pass
+ elif exc.errno in [
+ errno.ETIMEDOUT, errno.EHOSTUNREACH, errno.ENETUNREACH
+ ]:
+ pass
+ else:
+ do_print = True
+ elif (self._response_type == ServerResponseType.JSON
+ and isinstance(exc, json.decoder.JSONDecodeError)):
+ pass
+ 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)
-def serverget(
+def master_server_get(
request: str,
data: Dict[str, Any],
callback: Optional[ServerCallbackType] = None,
@@ -170,7 +177,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/_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
new file mode 100644
index 00000000..f0592a6f
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_player.py
@@ -0,0 +1,330 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Player related functionality."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, TypeVar, Generic, cast
+
+import _ba
+from ba._error import (SessionPlayerNotFoundError, print_exception,
+ ActorNotFoundError)
+from ba._messages import DeathType, DieMessage
+
+if TYPE_CHECKING:
+ from typing import (Type, Optional, Sequence, Dict, Any, Union, Tuple,
+ Callable)
+ import ba
+
+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
+
+
+@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.
+
+ Category: Gameplay Classes
+
+ 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.
+
+ """
+
+ # 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]
+ _expired: bool
+ _postinited: bool
+ _customdata: 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.
+
+ (internal)
+ """
+ from ba._nodeactor import NodeActor
+
+ # 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
+ self._sessionplayer = sessionplayer
+ self.character = sessionplayer.character
+ self.color = sessionplayer.color
+ self.highlight = sessionplayer.highlight
+ self._team = cast(TeamType, sessionplayer.sessionteam.activityteam)
+ assert self._team is not None
+ self._customdata = {}
+ self._expired = False
+ self._postinited = True
+ node = _ba.newnode('player', attrs={'playerID': sessionplayer.id})
+ self._nodeactor = NodeActor(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._customdata
+
+ 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}.')
+
+ self._nodeactor = None
+ self.actor = None
+ del self._team
+ del self._customdata
+
+ 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 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
+ 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._customdata
+
+ @property
+ def sessionplayer(self) -> ba.SessionPlayer:
+ """Return the ba.SessionPlayer corresponding to this Player.
+
+ Throws a ba.SessionPlayerNotFoundError if it does not exist.
+ """
+ assert self._postinited
+ if bool(self._sessionplayer):
+ return self._sessionplayer
+ raise 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.
+ """
+ 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 ba.Actor.
+
+ If the player currently has no actor, raises a ba.ActorNotFoundError.
+ """
+ assert self._postinited
+ assert not self._expired
+ if self.actor is None:
+ raise ActorNotFoundError
+ 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.
+ """
+ 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
+
+ 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:
+ """is_alive() -> bool
+
+ 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]:
+ """get_icon() -> Dict[str, Any]
+
+ 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 assigninput(self, inputtype: Union[ba.InputType, Tuple[ba.InputType,
+ ...]],
+ call: Callable) -> None:
+ """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.
+ """
+ assert self._postinited
+ assert not self._expired
+ return self._sessionplayer.assigninput(type=inputtype, call=call)
+
+ def resetinput(self) -> None:
+ """resetinput() -> None
+
+ Clears out the player's assigned input actions.
+ """
+ assert self._postinited
+ assert not self._expired
+ self._sessionplayer.resetinput()
+
+ def __bool__(self) -> bool:
+ 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 those top level
+ classes 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 should 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
+# 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.
+
+ 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
+ """
+ assert isinstance(player, (totype, type(None)))
+ return player
diff --git a/assets/src/ba_data/python/ba/_playlist.py b/assets/src/ba_data/python/ba/_playlist.py
index b50b1c6c..1f31ee6d 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
@@ -46,7 +28,7 @@ def filter_playlist(playlist: PlaylistType,
# pylint: disable=too-many-locals
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
- from ba import _meta
+ import _ba
from ba import _map
from ba import _general
from ba import _gameactivity
@@ -54,7 +36,7 @@ def filter_playlist(playlist: PlaylistType,
unowned_maps: Sequence[str]
if remove_unowned or mark_unowned:
unowned_maps = _map.get_unowned_maps()
- unowned_game_types = _meta.get_unowned_game_types()
+ unowned_game_types = _ba.app.meta.get_unowned_game_types()
else:
unowned_maps = []
unowned_game_types = set()
@@ -80,7 +62,7 @@ def filter_playlist(playlist: PlaylistType,
# the actual game class. add successful ones to our initial list
# to present to the user.
if not isinstance(entry['type'], str):
- raise Exception('invalid entry format')
+ raise TypeError('invalid entry format')
try:
# Do some type filters for backwards compat.
if entry['type'] in ('Assault.AssaultGame',
@@ -151,11 +133,10 @@ def filter_playlist(playlist: PlaylistType,
entry['is_unowned_game'] = True
# Make sure all settings the game defines are present.
- neededsettings = gameclass.get_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/_plugin.py b/assets/src/ba_data/python/ba/_plugin.py
new file mode 100644
index 00000000..cf4251cf
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_plugin.py
@@ -0,0 +1,96 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Plugin related functionality."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from dataclasses import dataclass
+import _ba
+
+if TYPE_CHECKING:
+ from typing import List, Dict
+ import ba
+
+
+class PluginSubsystem:
+ """Subsystem for plugin handling in the app.
+
+ Category: App Classes
+
+ Access the single shared instance of this class at 'ba.app.plugins'.
+ """
+
+ def __init__(self) -> None:
+ self.potential_plugins: List[ba.PotentialPlugin] = []
+ self.active_plugins: Dict[str, ba.Plugin] = {}
+
+ def on_app_launch(self) -> None:
+ """Should be called at app launch time."""
+ # 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()')
+
+ def load_plugins(self) -> None:
+ """(internal)"""
+ from ba._general import getclass
+
+ # 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] = _ba.app.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}')
+
+
+@dataclass
+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: 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.
+ """
+
+ def on_app_launch(self) -> None:
+ """Called when the app is being launched."""
diff --git a/assets/src/ba_data/python/ba/_powerup.py b/assets/src/ba_data/python/ba/_powerup.py
index 7dc69357..7dd895ce 100644
--- a/assets/src/ba_data/python/ba/_powerup.py
+++ b/assets/src/ba_data/python/ba/_powerup.py
@@ -1,24 +1,7 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
from typing import TYPE_CHECKING
@@ -31,7 +14,6 @@ if TYPE_CHECKING:
@dataclass
class PowerupMessage:
- # noinspection PyUnresolvedReferences
"""A message telling an object to accept a powerup.
Category: Message Classes
@@ -44,14 +26,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/_profile.py b/assets/src/ba_data/python/ba/_profile.py
index b49e04e7..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
@@ -35,7 +17,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]]:
@@ -50,16 +32,16 @@ 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']
- except Exception:
+ is_global = appconfig['Player Profiles'][profilename]['global']
+ except KeyError:
is_global = False
if is_global:
try:
- icon = bs_config['Player Profiles'][profilename]['icon']
- except Exception:
+ icon = appconfig['Player Profiles'][profilename]['icon']
+ except KeyError:
icon = _ba.charstr(SpecialChar.LOGO)
else:
icon = ''
@@ -71,36 +53,36 @@ 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
- if _ba.app.kiosk_mode and profilename is None:
+ # Special case: when being asked for a random color in kiosk mode,
+ # always return default purple.
+ 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:
try:
assert profilename is not None
color = profiles[profilename]['color']
- except Exception:
- # key off name if possible
+ except (KeyError, AssertionError):
+ # 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 Exception:
- # key off name if possible
+ except (KeyError, AssertionError):
+ # 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/_score.py b/assets/src/ba_data/python/ba/_score.py
new file mode 100644
index 00000000..d1cbe52c
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_score.py
@@ -0,0 +1,56 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""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 ScoreConfig:
+ """Settings for how a game handles scores.
+
+ Category: Gameplay Classes
+
+ Attributes:
+
+ 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/ba/_servermode.py b/assets/src/ba_data/python/ba/_servermode.py
index 0ffd8fa8..ec540d3b 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
@@ -26,14 +8,14 @@ import time
from typing import TYPE_CHECKING
from efro.terminal import Clr
-from ba._enums import TimeType
-from ba._freeforallsession import FreeForAllSession
-from ba._dualteamsession import DualTeamSession
from bacommon.servermanager import (ServerCommand, StartServerModeCommand,
ShutdownCommand, ShutdownReason,
ChatMessageCommand, ScreenMessageCommand,
ClientListCommand, KickCommand)
import _ba
+from ba._enums import TimeType
+from ba._freeforallsession import FreeForAllSession
+from ba._dualteamsession import DualTeamSession
if TYPE_CHECKING:
from typing import Optional, Dict, Any, Type
@@ -65,6 +47,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.
@@ -137,7 +120,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']
@@ -183,7 +166,7 @@ class ServerController:
return False
def _execute_shutdown(self) -> None:
- from ba._lang import Lstr
+ from ba._language import Lstr
if self._executing_shutdown:
return
self._executing_shutdown = True
@@ -192,19 +175,19 @@ class ServerController:
_ba.screenmessage(Lstr(resource='internal.serverRestartingText'),
color=(1, 0.5, 0.0))
print(f'{Clr.SBLU}Exiting for server-restart'
- f' at {timestrval}{Clr.RST}')
+ f' at {timestrval}.{Clr.RST}')
else:
_ba.screenmessage(Lstr(resource='internal.serverShuttingDownText'),
color=(1, 0.5, 0.0))
print(f'{Clr.SBLU}Exiting for server-shutdown'
- f' at {timestrval}{Clr.RST}')
+ f' at {timestrval}.{Clr.RST}')
with _ba.Context('ui'):
_ba.timer(2.0, _ba.quit, timetype=TimeType.REAL)
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(),
@@ -241,6 +224,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:
@@ -319,9 +303,11 @@ class ServerController:
if self._first_run:
curtimestr = time.strftime('%c')
- print(f'{Clr.BLD}{Clr.BLU}BallisticaCore {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
@@ -339,15 +325,28 @@ 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)
_ba.set_public_party_stats_url(self._config.stats_url)
_ba.set_public_party_enabled(self._config.party_is_public)
- # And here we go.
- _ba.new_host_session(sessiontype)
+ # And here.. we.. go.
+ if self._config.stress_test_players is not None:
+ # Special case: run a stress test.
+ from ba.internal import run_stress_test
+ run_stress_test(playlist_type='Random',
+ playlist_name='__default__',
+ player_count=self._config.stress_test_players,
+ round_duration=30)
+ else:
+ _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/ba/_session.py b/assets/src/ba_data/python/ba/_session.py
index 1a5c4a7d..9405ec48 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
@@ -25,16 +7,17 @@ import weakref
from typing import TYPE_CHECKING
import _ba
+from ba._error import print_error, print_exception, NodeNotFoundError
+from ba._language 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
class Session:
- """Defines a high level series of activities with a common purpose.
+ """Defines a high level series of ba.Activities with a common purpose.
category: Gameplay Classes
@@ -47,21 +30,22 @@ class Session:
Attributes:
- 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
@@ -69,29 +53,44 @@ 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
+ 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.
+
+ 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
+ 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.
- campaign: Optional[ba.Campaign]
lobby: ba.Lobby
max_players: int
min_players: int
- players: List[ba.Player]
- teams: List[ba.Team]
+ sessionplayers: List[ba.SessionPlayer]
+ customdata: dict
+ sessionteams: List[ba.SessionTeam]
def __init__(self,
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
@@ -102,11 +101,12 @@ 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._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
@@ -125,7 +125,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:
@@ -143,251 +144,173 @@ class Session:
# print('Would set host-session asset-reqs to:',
# required_asset_packages)
- # First thing, wire up our internal engine data.
+ # Init our C++ layer data.
self._sessiondata = _ba.register_session(self)
+ # Should remove this if possible.
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)
- 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._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
-
- # 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
- 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.sessionteams = []
+ self.sessionplayers = []
self.min_players = min_players
self.max_players = max_players
- # Create Teams.
- if self._use_teams:
+ self.customdata = {}
+ 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)
+ self._next_activity: Optional[ba.Activity] = None
+ self._wants_to_end = False
+ self._ending = False
+ self._activity_should_end_immediately = False
+ self._activity_should_end_immediately_results: (
+ Optional[ba.GameResults]) = None
+ self._activity_should_end_immediately_delay = 0.0
+
+ # 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):
- team = Team(team_id=self._next_team_id,
- name=GameActivity.get_team_display_string(
- team_names[i]),
- color=color)
- self.teams.append(team)
+ team = SessionTeam(team_id=self._next_team_id,
+ name=GameActivity.get_team_display_string(
+ team_names[i]),
+ color=color)
+ self.sessionteams.append(team)
self._next_team_id += 1
-
try:
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).
- sharedobj('globals')
+ # Instantiate our session globals node which will apply its settings.
+ self._sessionglobalsnode = _ba.newnode('sessionglobals')
@property
- def use_teams(self) -> bool:
- """(internal)"""
- return self._use_teams
+ def sessionglobalsnode(self) -> ba.Node:
+ """The sessionglobals ba.Node for the session."""
+ node = self._sessionglobalsnode
+ if not node:
+ raise NodeNotFoundError()
+ return node
- @property
- def use_team_colors(self) -> bool:
- """(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:
- 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).
_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'))
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
- # pylint: disable=too-many-branches
- # pylint: disable=cyclic-import
- from ba._freeforallsession import FreeForAllSession
- from ba._lang import Lstr
- from ba import _error
+ def on_player_leave(self, sessionplayer: ba.SessionPlayer) -> None:
+ """Called when a previously-accepted ba.SessionPlayer leaves."""
- # 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.sessionplayers:
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 is still in the lobby; simply remove them.
+ 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.sessionteam
+ assert sessionteam is not None
+
+ _ba.screenmessage(
+ Lstr(resource='playerLeftText',
+ subs=[('${PLAYER}', sessionplayer.getname(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.activityplayer
+ 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:
+ self._remove_player_team(sessionteam, activity)
+
+ # Now remove them from the session list.
+ self.sessionplayers.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.activityteam 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.sessionteams:
+ try:
+ self.sessionteams.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.leave()
+ 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.
@@ -395,49 +318,36 @@ 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 import _error
from ba._activitytypes import EndSessionActivity
from ba._enums import TimeType
with _ba.Context(self):
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
- _error.print_error(
- 'launch_end_session_activity called twice (since_last=' +
+ 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._launch_end_session_activity_time = curtime
+ self.setactivity(_ba.newactivity(EndSessionActivity))
+ self._wants_to_end = False
+ 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,
- results: Any) -> None:
- # Run the subclass callback in the session context.
- try:
- 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)
-
def end_activity(self, activity: ba.Activity, results: Any, delay: float,
force: bool) -> None:
"""Commence shutdown of a ba.Activity (if not already occurring).
@@ -457,7 +367,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:
@@ -473,107 +387,74 @@ 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
- 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
- def set_activity(self, activity: ba.Activity) -> None:
+ 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 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)
"""
- # 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(
- 'Session.set_activity() cannot be called recursively.')
+ # Make sure we don't get called recursively.
+ _rlock = self._SetActivityScopedLock(self)
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
+ prev_globals = (prev_activity.globalsnode
+ if prev_activity is not None else None)
- if prev_activity is not None:
- with _ba.Context(prev_activity):
- gprev = sharedobj('globals')
- else:
- gprev = 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 +467,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.expire,
+ timetype=TimeType.REAL)
self._in_set_activity = False
def getactivity(self) -> Optional[ba.Activity]:
@@ -631,34 +492,39 @@ class Session:
"""
return []
- def _request_player(self, player: ba.Player) -> bool:
+ 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(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 native layer when a player wants to join."""
# If we're ending, allow no new players.
if self._ending:
return False
- # Ask the user.
+ # Ask the ba.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(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(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.sessionplayers.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('Error in lobby.add_chooser().')
return result
@@ -674,149 +540,158 @@ 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
+ # 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
- # 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.
- self.lobby.remove_all_choosers_and_kick_players()
- activity = self._activity_weak()
- assert activity is not None
- activity.begin(self)
+ # 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 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."""
- from ba._lang import Lstr
lobby = chooser.lobby
activity = self._activity_weak()
- # 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()
+ # 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
- # 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:
+ # In joining-activities, we wait till all choosers are ready
+ # and then create all players at once.
+ 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:
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 transitioning_out_activity_was_freed(
+ self, can_show_ad_on_death: bool) -> None:
+ """(internal)"""
+ from ba._apputils import garbage_collect
+
+ # 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()
+
+ with _ba.Context(self):
+ if can_show_ad_on_death:
+ _ba.app.ads.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()
+ assert sessionplayer in self.sessionplayers, (
+ '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.resetinput()
- # 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.
+ # 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:
+ 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.getname(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()
+ if self.use_teams:
+ sessionteam = chooser.sessionteam
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
- try:
- with _ba.Context(self):
- self.on_team_join(team)
- except Exception:
- _error.print_exception(f'exception in on_team_join for {self}')
+ sessionteam = SessionTeam(
+ team_id=our_team_id,
+ color=chooser.get_color(),
+ name=chooser.getplayer().getname(full=True, icon=False),
+ )
+ # Add player's team to the Session.
+ self.sessionteams.append(sessionteam)
+
+ with _ba.Context(self):
+ try:
+ self.on_team_join(sessionteam)
+ except Exception:
+ print_exception(f'Error 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.setdata(team=sessionteam,
+ character=chooser.get_character_name(),
+ color=chooser.get_color(),
+ highlight=chooser.get_highlight())
- self.stats.register_player(player)
+ self.stats.register_sessionplayer(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/_settings.py b/assets/src/ba_data/python/ba/_settings.py
new file mode 100644
index 00000000..1b3e4040
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_settings.py
@@ -0,0 +1,84 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""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/_stats.py b/assets/src/ba_data/python/ba/_stats.py
index d62ac24f..bf3becb0 100644
--- a/assets/src/ba_data/python/ba/_stats.py
+++ b/assets/src/ba_data/python/ba/_stats.py
@@ -1,25 +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.
-# -----------------------------------------------------------------------------
"""Functionality related to scores and statistics."""
-
from __future__ import annotations
import random
@@ -28,6 +9,8 @@ from typing import TYPE_CHECKING
from dataclasses import dataclass
import _ba
+from ba._error import (print_exception, print_error, SessionTeamNotFoundError,
+ SessionPlayerNotFoundError, NotFoundError)
if TYPE_CHECKING:
import ba
@@ -37,7 +20,6 @@ if TYPE_CHECKING:
@dataclass
class PlayerScoredMessage:
- # noinspection PyUnresolvedReferences
"""Informs something that a ba.Player scored.
Category: Message Classes
@@ -61,8 +43,8 @@ class PlayerRecord:
"""
character: str
- def __init__(self, name: str, name_full: str, player: ba.Player,
- 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
@@ -74,43 +56,43 @@ 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_sessionplayer: Optional[ba.SessionPlayer] = 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.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()
+ assert self._sessionteam is not None
+ team = self._sessionteam()
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."""
- if not self._player:
- from ba._error import PlayerNotFoundError
- raise PlayerNotFoundError()
- return self._player
+ Raises a ba.SessionPlayerNotFoundError if the player
+ no longer exists.
+ """
+ if not self._sessionplayer:
+ raise SessionPlayerNotFoundError()
+ return self._sessionplayer
- 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
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,28 +109,29 @@ class PlayerRecord:
return stats.getactivity()
return None
- def associate_with_player(self, player: ba.Player) -> 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_sessionplayer(self,
+ sessionplayer: ba.SessionPlayer) -> None:
+ """Associate this entry with a ba.SessionPlayer."""
+ self._sessionteam = weakref.ref(sessionplayer.sessionteam)
+ self.character = sessionplayer.character
+ self._last_sessionplayer = 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.Player:
+ def get_last_sessionplayer(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."""
# FIXME Clean this up.
# pylint: disable=too-many-statements
- from ba._lang import Lstr
+ from ba._language import Lstr
from ba._general import Call
self._multi_kill_count += 1
stats = self._stats()
@@ -203,16 +186,21 @@ 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[ba.Vec3] = None
+ if self._sessionplayer:
+ 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(
@@ -256,16 +244,15 @@ 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)
# 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,17 +290,16 @@ class Stats:
s_player.accum_killed_count = 0
s_player.streak = 0
- def register_player(self, player: ba.Player) -> None:
- """Register a player with this score-set."""
- name = player.get_name()
- name_full = player.get_name(full=True)
- try:
+ 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)
- except Exception:
- # FIXME: Shouldn't use top level Exception catch for logic.
- # Should only have this as a fallback and always log it.
+ self._player_records[name].associate_with_sessionplayer(player)
+ else:
+ name_full = player.getname(full=True)
self._player_records[name] = PlayerRecord(name, name_full, player,
self)
@@ -324,16 +310,11 @@ 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()
- if lastplayer and lastplayer.get_name() == record_id:
+ lastplayer = record.get_last_sessionplayer()
+ if lastplayer and lastplayer.getname() == record_id:
records[record_id] = record
return records
- def player_got_hit(self, player: ba.Player) -> None:
- """Call this when a player got hit."""
- s_player = self._player_records[player.get_name()]
- s_player.streak = 0
-
def player_scored(self,
player: ba.Player,
base_points: int = 1,
@@ -360,9 +341,9 @@ class Stats:
from bastd.actor.popuptext import PopupText
from ba import _math
from ba._gameactivity import GameActivity
- from ba._lang import Lstr
+ from ba._language import Lstr
del victim_player # Currently unused.
- name = player.get_name()
+ name = player.getname()
s_player = self._player_records[name]
if kill:
@@ -382,14 +363,13 @@ 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)]),
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 +410,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
@@ -449,8 +428,8 @@ class Stats:
killed: bool = False,
killer: ba.Player = None) -> None:
"""Should be called when a player is killed."""
- from ba._lang import Lstr
- name = player.get_name()
+ from ba._language import Lstr
+ name = player.getname()
prec = self._player_records[name]
prec.streak = 0
if killed:
@@ -458,17 +437,17 @@ 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()),
+ killer.getname()),
('${VICTIM}', name)]),
top=True,
color=killer.color,
@@ -476,7 +455,7 @@ class Stats:
else:
_ba.screenmessage(Lstr(resource='nameKilledText',
subs=[('${NAME}',
- killer.get_name()),
+ killer.getname()),
('${VICTIM}', name)]),
top=True,
color=killer.color,
@@ -488,5 +467,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/_store.py b/assets/src/ba_data/python/ba/_store.py
index 262ddeee..fd4e5bfc 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
@@ -39,15 +21,16 @@ def get_store_item(item: str) -> Dict[str, Any]:
def get_store_item_name_translated(item_name: str) -> ba.Lstr:
"""Return a ba.Lstr for a store item name."""
# pylint: disable=cyclic-import
- from ba import _lang
+ from ba import _language
from ba import _map
item_info = get_store_item(item_name)
if item_name.startswith('characters.'):
- return _lang.Lstr(translate=('characterNames', item_info['character']))
+ return _language.Lstr(translate=('characterNames',
+ item_info['character']))
if item_name in ['upgrades.pro', 'pro']:
- return _lang.Lstr(resource='store.bombSquadProNameText',
- subs=[('${APP_NAME}',
- _lang.Lstr(resource='titleText'))])
+ return _language.Lstr(resource='store.bombSquadProNameText',
+ subs=[('${APP_NAME}',
+ _language.Lstr(resource='titleText'))])
if item_name.startswith('maps.'):
map_type: Type[ba.Map] = item_info['map_type']
return _map.get_map_display_string(map_type.name)
@@ -55,8 +38,8 @@ def get_store_item_name_translated(item_name: str) -> ba.Lstr:
gametype: Type[ba.GameActivity] = item_info['gametype']
return gametype.get_display_string()
if item_name.startswith('icons.'):
- return _lang.Lstr(resource='editProfileWindow.iconText')
- raise Exception('unrecognized item: ' + item_name)
+ return _language.Lstr(resource='editProfileWindow.iconText')
+ raise ValueError('unrecognized item: ' + item_name)
def get_store_item_display_size(item_name: str) -> Tuple[float, float]:
@@ -457,7 +440,6 @@ def get_available_sale_time(tab: str) -> Optional[int]:
# pylint: disable=too-many-locals
try:
import datetime
- from ba._account import have_pro
from ba._enums import TimeType, TimeFormat
app = _ba.app
sale_times: List[Optional[int]] = []
@@ -465,7 +447,7 @@ def get_available_sale_time(tab: str) -> Optional[int]:
# Calc time for our pro sale (old special case).
if tab == 'extras':
config = app.config
- if have_pro():
+ if app.accounts.have_pro():
return None
# If we haven't calced/loaded start times yet.
@@ -494,7 +476,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
@@ -518,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/ba/_team.py b/assets/src/ba_data/python/ba/_team.py
index 31e2e9d1..67e254b2 100644
--- a/assets/src/ba_data/python/ba/_team.py
+++ b/assets/src/ba_data/python/ba/_team.py
@@ -1,117 +1,212 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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 Team class."""
+"""Team related functionality."""
+
from __future__ import annotations
-from typing import TYPE_CHECKING
+import weakref
+from typing import TYPE_CHECKING, TypeVar, Generic
+
+from ba._error import print_exception
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
- 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:
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
- 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.
"""
# Annotate our attr types at the class level so they're introspectable.
name: Union[ba.Lstr, str]
- color: Tuple[float, ...]
- players: List[ba.Player]
- gamedata: Dict
- sessiondata: Dict
+ color: Tuple[float, ...] # FIXME: can't we make this fixed len?
+ players: List[ba.SessionPlayer]
+ customdata: 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 = {}
+ self.customdata = {}
+ self.activityteam: Optional[Team] = None
- # 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:
+ def leave(self) -> None:
"""(internal)"""
- self.reset_gamedata()
- object.__setattr__(self, 'players', [])
+ self.customdata = {}
- def reset_gamedata(self) -> None:
- """(internal)"""
- object.__setattr__(self, 'gamedata', {})
- def reset_sessiondata(self) -> None:
- """(internal)"""
- object.__setattr__(self, 'sessiondata', {})
+PlayerType = TypeVar('PlayerType', bound='ba.Player')
- 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)
+
+class Team(Generic[PlayerType]):
+ """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).
+ players: List[PlayerType]
+ id: int
+ name: Union[ba.Lstr, str]
+ color: Tuple[float, ...] # FIXME: can't we make this fixed length?
+ _sessionteam: ReferenceType[SessionTeam]
+ _expired: bool
+ _postinited: bool
+ _customdata: 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)
+ """
+
+ # 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
+ self.name = sessionteam.name
+ self.color = sessionteam.color
+ self._customdata = {}
+ self._expired = False
+ self._postinited = True
+
+ 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._customdata = {}
+ self._expired = False
+ self._postinited = True
+
+ @property
+ 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
+ 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._customdata
+
+ def leave(self) -> None:
+ """Called when the Team leaves a running game.
+
+ (internal)
+ """
+ assert self._postinited
+ assert not self._expired
+ del self._customdata
+ 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._customdata
+ del self.players
+
+ def on_expire(self) -> None:
+ """Can be overridden to handle team expiration."""
+
+ @property
+ def sessionteam(self) -> SessionTeam:
+ """Return the ba.SessionTeam corresponding to this Team.
+
+ 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:
+ 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 those top level
+ classes 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 should 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 7c13f6ab..afa8519e 100644
--- a/assets/src/ba_data/python/ba/_teamgame.py
+++ b/assets/src/ba_data/python/ba/_teamgame.py
@@ -1,33 +1,15 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-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._gameresults import GameResults
from ba._dualteamsession import DualTeamSession
if TYPE_CHECKING:
@@ -35,8 +17,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 TeamGameActivity(GameActivity):
+
+class TeamGameActivity(GameActivity[PlayerType, TeamType]):
"""Base class for teams and free-for-all mode games.
Category: Gameplay Classes
@@ -55,14 +40,14 @@ class TeamGameActivity(GameActivity):
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.
+ # 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
@@ -74,8 +59,8 @@ class TeamGameActivity(GameActivity):
# (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:
+ attrname = '_have_shown_ctrl_help_overlay'
+ if not getattr(self.session, attrname, False):
delay = 4.0
lifespan = 10.0
if self.slow_motion:
@@ -85,7 +70,7 @@ class TeamGameActivity(GameActivity):
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()
@@ -93,18 +78,17 @@ class TeamGameActivity(GameActivity):
# Award a few achievements.
if isinstance(self.session, FreeForAllSession):
if len(self.players) >= 2:
- from ba import _achievement
- _achievement.award_local_achievement('Free Loader')
+ _ba.app.ach.award_local_achievement('Free Loader')
elif isinstance(self.session, DualTeamSession):
if len(self.players) >= 4:
from ba import _achievement
- _achievement.award_local_achievement('Team Player')
+ _ba.app.ach.award_local_achievement('Team Player')
except Exception:
from ba import _error
_error.print_exception()
def spawn_player_spaz(self,
- player: ba.Player,
+ player: PlayerType,
position: Sequence[float] = None,
angle: float = None) -> PlayerSpaz:
"""
@@ -117,13 +101,14 @@ 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)
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,
@@ -146,8 +131,9 @@ class TeamGameActivity(GameActivity):
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)
+ assert isinstance(results, GameResults)
if do_announce and isinstance(session, MultiTeamSession):
session.announce_game_results(
self,
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
new file mode 100644
index 00000000..c5af590a
--- /dev/null
+++ b/assets/src/ba_data/python/ba/_ui.py
@@ -0,0 +1,167 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""User interface related functionality."""
+
+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, Type
+ from ba.ui import UICleanupCheck
+ import ba
+
+
+class UISubsystem:
+ """Consolidated UI functionality for the app.
+
+ Category: App Classes
+
+ To use this class, access the single instance of it at 'ba.app.ui'.
+ """
+
+ 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._uiscale: ba.UIScale
+
+ interfacetype = env['ui_scale']
+ if interfacetype == 'large':
+ self._uiscale = UIScale.LARGE
+ elif interfacetype == 'medium':
+ self._uiscale = UIScale.MEDIUM
+ elif interfacetype == 'small':
+ self._uiscale = UIScale.SMALL
+ else:
+ raise RuntimeError(f'Invalid UIScale value: {interfacetype}')
+
+ self.window_states: Dict[Type, Any] = {} # 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)
+
+ # Switch our overall game selection UI flow between Play and
+ # Private-party playlist selection modes; should do this in
+ # a more elegant way once we revamp high level UI stuff a bit.
+ self.selecting_private_party_playlist: bool = False
+
+ @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_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.
+ # 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 should un-break
+ # things.
+ def _delay_kill() -> None:
+ import time
+ if existing:
+ print(f'Killing old main_menu_window'
+ f' when called at: {frameline} t={time.time():.3f}')
+ 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/deprecated.py b/assets/src/ba_data/python/ba/deprecated.py
index fe800053..de3ff2aa 100644
--- a/assets/src/ba_data/python/ba/deprecated.py
+++ b/assets/src/ba_data/python/ba/deprecated.py
@@ -1,31 +1,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.
-# -----------------------------------------------------------------------------
"""Deprecated functionality.
Classes or functions can be relocated here when they are deprecated.
Any code using them should migrate to alternative methods, as
deprecated items will eventually be fully removed.
"""
-
-# pylint: disable=unused-import
-
-# The Lstr class should be used for all string resources.
-from ba._lang import get_resource, translate
diff --git a/assets/src/ba_data/python/ba/internal.py b/assets/src/ba_data/python/ba/internal.py
index 4a9f5386..1d852ee1 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
@@ -34,27 +16,17 @@ from ba._appconfig import commit_app_config
from ba._input import (get_device_value, get_input_map_hash,
get_input_device_config)
from ba._general import getclass, json_prep, get_type_name
-from ba._account import (on_account_state_changed,
- handle_account_gained_tickets, have_pro_options,
- have_pro, cache_tournament_info,
- ensure_have_account_player_profile,
- get_purchased_icons, get_cached_league_rank_data,
- get_league_rank_points, cache_league_rank_data)
from ba._activitytypes import JoinActivity, ScoreScreenActivity
-from ba._achievement import (get_achievement, set_completed_achievements,
- display_achievement_banner,
- get_achievements_for_coop_level)
from ba._apputils import (is_browser_likely_available, get_remote_app_name,
- should_submit_debug_info, show_ad, show_ad_2)
+ should_submit_debug_info)
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
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/ba/macmusicapp.py b/assets/src/ba_data/python/ba/macmusicapp.py
index 94a3b48f..c8a64d75 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
@@ -86,7 +68,7 @@ class _MacMusicAppThread(threading.Thread):
def run(self) -> None:
"""Run the Music.app thread."""
from ba._general import Call
- from ba._lang import Lstr
+ from ba._language import Lstr
from ba._enums import TimeType
_ba.set_thread_name('BA_MacMusicAppThread')
_ba.mac_music_app_init()
@@ -230,7 +212,6 @@ class _MacMusicAppThread(threading.Thread):
def _play_current_playlist(self) -> None:
try:
- from ba import _lang
from ba._general import Call
assert self._current_playlist is not None
if _ba.mac_music_app_play_playlist(self._current_playlist):
@@ -238,8 +219,8 @@ class _MacMusicAppThread(threading.Thread):
else:
_ba.pushcall(Call(
_ba.screenmessage,
- _lang.get_resource('playlistNotFoundText') + ': \'' +
- self._current_playlist + '\'', (1, 0, 0)),
+ _ba.app.lang.get_resource('playlistNotFoundText') +
+ ': \'' + self._current_playlist + '\'', (1, 0, 0)),
from_other_thread=True)
except Exception:
from ba import _error
diff --git a/assets/src/ba_data/python/ba/_modutils.py b/assets/src/ba_data/python/ba/modutils.py
similarity index 62%
rename from assets/src/ba_data/python/ba/_modutils.py
rename to assets/src/ba_data/python/ba/modutils.py
index 11e33021..904711f8 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
@@ -27,7 +9,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:
@@ -35,7 +17,7 @@ def get_human_readable_user_scripts_path() -> str:
This is NOT a valid filesystem path; may be something like "(SD Card)".
"""
- from ba import _lang
+ from ba import _language
app = _ba.app
path: Optional[str] = app.python_directory_user
if path is None:
@@ -50,23 +32,30 @@ def get_human_readable_user_scripts_path() -> str:
if (ext_storage_path is not None
and app.python_directory_user.startswith(ext_storage_path)):
path = ('<' +
- _lang.Lstr(resource='externalStorageText').evaluate() +
+ _language.Lstr(resource='externalStorageText').evaluate() +
'>' + app.python_directory_user[len(ext_storage_path):])
return path
+def _request_storage_permission() -> bool:
+ """If needed, requests storage permission from the user (& return true)."""
+ from ba._language 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 +96,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_ba
- dst_dir = path + '_tmp'
- filenames = os.listdir(app.python_directory_ba)
- 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 +139,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 38a097c8..5257e0aa 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
@@ -71,7 +53,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(),
@@ -80,9 +62,9 @@ class OSMusicPlayer(MusicPlayer):
def _on_play_folder_cb(self,
result: Union[str, List[str]],
error: Optional[str] = None) -> None:
- from ba import _lang
+ from ba import _language
if error is not None:
- rstr = (_lang.Lstr(
+ rstr = (_language.Lstr(
resource='internal.errorPlayingMusicText').evaluate())
if isinstance(result, str):
err_str = (rstr.replace('${MUSIC}', os.path.basename(result)) +
@@ -121,8 +103,9 @@ class _PickFolderSongThread(threading.Thread):
self._path = path
def run(self) -> None:
- from ba import _lang
+ from ba import _language
from ba._general import Call
+ do_print_error = True
try:
_ba.set_thread_name('BA_PickFolderSongThread')
all_files: List[str] = []
@@ -134,14 +117,16 @@ class _PickFolderSongThread(threading.Thread):
all_files.insert(random.randrange(len(all_files) + 1),
root + '/' + fname)
if not all_files:
- raise Exception(
- _lang.Lstr(resource='internal.noMusicFilesInFolderText').
- evaluate())
+ do_print_error = False
+ raise RuntimeError(
+ _language.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/ba/ui/__init__.py b/assets/src/ba_data/python/ba/ui/__init__.py
index d1745291..e65453f1 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
@@ -29,6 +11,7 @@ from typing import TYPE_CHECKING, cast, Type
import _ba
from ba._enums import TimeType
+from ba._general import print_active_refs
if TYPE_CHECKING:
from typing import Optional, List, Any
@@ -47,9 +30,13 @@ class Window:
Category: User Interface Classes
"""
- def __init__(self, root_widget: ba.Widget):
+ def __init__(self, root_widget: ba.Widget, cleanupcheck: bool = True):
self._root_widget = root_widget
+ # Complain if we outlive our root widget.
+ if cleanupcheck:
+ uicleanupcheck(self, root_widget)
+
def get_root_widget(self) -> ba.Widget:
"""Return the root widget."""
return self._root_widget
@@ -127,11 +114,11 @@ class UIEntry:
if self._name == 'mainmenu':
from bastd.ui import mainmenu
return cast(Type[UILocation], mainmenu.MainMenuWindow)
- raise Exception('unknown ui class ' + str(self._name))
+ raise ValueError('unknown ui class ' + str(self._name))
class UIController:
- """Wrangles UILocations.
+ """Wrangles ba.UILocations.
Category: User Interface Classes
"""
@@ -192,15 +179,18 @@ def uicleanupcheck(obj: Any, widget: ba.Widget) -> None:
if DEBUG_UI_CLEANUP_CHECKS:
print(f'adding uicleanup to {obj}')
if not isinstance(widget, _ba.Widget):
- raise Exception('widget arg is not a 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):
- widget.add_delete_callback(foobar)
- _ba.app.uicleanupchecks.append(
+ def foobar() -> None:
+ """Just testing."""
+ if DEBUG_UI_CLEANUP_CHECKS:
+ print('uicleanupcheck widget dying...')
+
+ widget.add_delete_callback(foobar)
+
+ _ba.app.ui.cleanupchecks.append(
UICleanupCheck(obj=weakref.ref(obj),
widget=widget,
widget_death_time=None))
@@ -208,10 +198,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.
@@ -231,7 +221,9 @@ def ui_upkeep() -> None:
print(
'WARNING:', obj,
'is still alive 5 second after its widget died;'
- ' you probably have a memory leak.')
+ ' you might have a memory leak.')
+ print_active_refs(obj)
+
else:
remainingchecks.append(check)
- app.uicleanupchecks = remainingchecks
+ ui.cleanupchecks = remainingchecks
diff --git a/assets/src/ba_data/python/bastd/__init__.py b/assets/src/ba_data/python/bastd/__init__.py
index ab76b753..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.
-# -----------------------------------------------------------------------------
-"""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/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/activity/coopjoin.py b/assets/src/ba_data/python/bastd/activity/coopjoin.py
index 048dfa68..1bb614a4 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
@@ -35,17 +17,21 @@ if TYPE_CHECKING:
class CoopJoinActivity(JoinActivity):
"""Join-screen for co-op mode."""
- def __init__(self, settings: Dict[str, Any]):
+ # We can assume our session is a CoopSession.
+ session: ba.CoopSession
+
+ def __init__(self, settings: dict):
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.getlevel(
+ 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 +39,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,
+ Text(self.session.campaign.getlevel(
+ self.session.campaign_level_name).displayname,
scale=1.3,
h_attach=Text.HAttach.CENTER,
h_align=Text.HAlign.CENTER,
@@ -70,12 +57,13 @@ 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
@@ -163,13 +151,15 @@ 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:
+ if not (ba.app.demo_mode or ba.app.arcade_mode):
achievements = [
- a for a in get_achievements_for_coop_level(levelname)
+ a
+ for a in ba.app.ach.achievements_for_coop_level(levelname)
if not a.complete
]
have_achievements = bool(achievements)
diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py
index 23604e2b..b8678cd0 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
@@ -28,7 +10,6 @@ from typing import TYPE_CHECKING
import _ba
import ba
-from ba.internal import get_achievements_for_coop_level
from bastd.actor.text import Text
from bastd.actor.zoomtext import ZoomText
@@ -38,17 +19,17 @@ 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]):
+ def __init__(self, settings: dict):
# 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
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
@@ -68,8 +49,8 @@ class CoopScoreScreen(ba.Activity):
self._campaign: ba.Campaign = settings['campaign']
self._have_achievements = bool(
- get_achievements_for_coop_level(self._campaign.name + ':' +
- settings['level']))
+ ba.app.ach.achievements_for_coop_level(self._campaign.name + ':' +
+ settings['level']))
self._account_type = (_ba.get_account_type() if
_ba.get_account_state() == 'signed_in' else None)
@@ -137,7 +118,10 @@ class CoopScoreScreen(ba.Activity):
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._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)))
@@ -149,8 +133,8 @@ class CoopScoreScreen(ba.Activity):
self._score_order: str
if 'score_order' in settings:
if not settings['score_order'] in ['increasing', 'decreasing']:
- raise Exception('Invalid score order: ' +
- settings['score_order'])
+ raise ValueError('Invalid score order: ' +
+ settings['score_order'])
self._score_order = settings['score_order']
else:
self._score_order = 'increasing'
@@ -159,8 +143,8 @@ class CoopScoreScreen(ba.Activity):
self._score_type: str
if 'score_type' in settings:
if not settings['score_type'] in ['points', 'time']:
- raise Exception('Invalid score type: ' +
- settings['score_type'])
+ raise ValueError('Invalid score type: ' +
+ settings['score_type'])
self._score_type = settings['score_type']
else:
self._score_type = 'points'
@@ -171,7 +155,7 @@ class CoopScoreScreen(ba.Activity):
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.getlevel(
self._level_name).get_score_version_string().replace(' ', '_')
# If game-center/etc scores are available we show our friends'
@@ -180,7 +164,7 @@ class CoopScoreScreen(ba.Activity):
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
@@ -319,7 +303,6 @@ class CoopScoreScreen(ba.Activity):
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
@@ -327,15 +310,7 @@ class CoopScoreScreen(ba.Activity):
# 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),
@@ -395,7 +370,8 @@ class CoopScoreScreen(ba.Activity):
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
@@ -461,7 +437,7 @@ class CoopScoreScreen(ba.Activity):
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:
@@ -510,7 +486,7 @@ class CoopScoreScreen(ba.Activity):
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
@@ -519,8 +495,8 @@ class CoopScoreScreen(ba.Activity):
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)
@@ -548,7 +524,7 @@ class CoopScoreScreen(ba.Activity):
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
@@ -577,18 +553,18 @@ class CoopScoreScreen(ba.Activity):
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} -',
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,
@@ -633,7 +609,7 @@ class CoopScoreScreen(ba.Activity):
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(
@@ -656,19 +632,19 @@ class CoopScoreScreen(ba.Activity):
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._player_info)) +
- ' Player']
- except Exception:
- our_high_scores = our_high_scores_all[str(len(self._player_info)) +
- ' Player'] = []
+
+ our_high_scores = our_high_scores_all.setdefault(
+ str(len(self._playerinfos)) + ' Player', [])
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._playerinfos]
}
]
our_high_scores.append(our_score)
@@ -679,13 +655,13 @@ class CoopScoreScreen(ba.Activity):
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:]
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',
@@ -696,7 +672,7 @@ class CoopScoreScreen(ba.Activity):
})
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))
@@ -783,7 +759,7 @@ class CoopScoreScreen(ba.Activity):
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
@@ -800,9 +776,15 @@ class CoopScoreScreen(ba.Activity):
(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(
+ f'Error calcing name_str for {display_scores}')
name_str = '-'
if display_scores[i] == our_score and not showed_ours:
flash = True
@@ -835,7 +817,7 @@ class CoopScoreScreen(ba.Activity):
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,
@@ -864,7 +846,8 @@ class CoopScoreScreen(ba.Activity):
transition_delay=2.8).autoretain()
assert self._game_name_str is not None
- achievements = get_achievements_for_coop_level(self._game_name_str)
+ achievements = ba.app.ach.achievements_for_coop_level(
+ self._game_name_str)
hval = -455
vval = -100
tdelay = 0.0
@@ -890,6 +873,7 @@ class CoopScoreScreen(ba.Activity):
# 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))
@@ -926,7 +910,7 @@ class CoopScoreScreen(ba.Activity):
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'.
@@ -1008,7 +992,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.
@@ -1080,7 +1064,7 @@ class CoopScoreScreen(ba.Activity):
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':
@@ -1140,7 +1124,7 @@ class CoopScoreScreen(ba.Activity):
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,
@@ -1177,8 +1161,8 @@ class CoopScoreScreen(ba.Activity):
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:
@@ -1213,8 +1197,9 @@ class CoopScoreScreen(ba.Activity):
try:
tournament_id = self.session.tournament_id
if tournament_id is not None:
- if tournament_id in ba.app.tournament_info:
- tourney_info = ba.app.tournament_info[tournament_id]
+ if tournament_id in ba.app.accounts.tournament_info:
+ tourney_info = ba.app.accounts.tournament_info[
+ tournament_id]
# pylint: disable=unbalanced-tuple-unpacking
pr1, pv1, pr2, pv2, pr3, pv3 = (
get_tournament_prize_strings(tourney_info))
@@ -1250,7 +1235,7 @@ class CoopScoreScreen(ba.Activity):
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:
@@ -1303,7 +1288,7 @@ class CoopScoreScreen(ba.Activity):
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,
@@ -1385,7 +1370,7 @@ class CoopScoreScreen(ba.Activity):
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/drawscore.py b/assets/src/ba_data/python/bastd/activity/drawscore.py
index e2fc96cd..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
@@ -26,6 +8,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 +17,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'),
@@ -54,4 +31,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..b031bb80 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
@@ -35,11 +17,12 @@ 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)
def on_begin(self) -> None:
- from ba.deprecated import get_resource
ba.set_analytics_screen('Teams Score Screen')
super().on_begin()
@@ -53,7 +36,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
# 'First to 4'.
session = self.session
assert isinstance(session, ba.MultiTeamSession)
- if get_resource('bestOfUseFirstToInstead'):
+ if ba.app.lang.get_resource('bestOfUseFirstToInstead'):
best_txt = ba.Lstr(resource='firstToSeriesText',
subs=[('${COUNT}',
str(session.get_series_length() / 2 + 1))
@@ -73,14 +56,14 @@ 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.sessionteams:
ba.timer(
i * 0.15 + 0.15,
ba.WeakCall(self._show_team_name, vval - i * height, team,
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._winner)
delay = 0.2
if scored:
delay = 1.2
@@ -99,9 +82,9 @@ 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:
- del kill_delay # unused arg
+ 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),
shiftposition=(-150, pos_v),
@@ -113,9 +96,9 @@ 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, 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),
@@ -127,10 +110,11 @@ 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:
- del kill_delay # unused arg
- ZoomText(str(team.sessiondata['score']),
+ 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(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 d20481e1..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
@@ -28,13 +10,13 @@ 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):
"""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.
@@ -60,13 +42,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.get_name(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.get_name(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
@@ -78,8 +64,8 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
delay3 += 1.5
ba.timer(0.3, ba.Call(ba.playsound, self._score_display_sound))
- results = self.settings['results']
- assert isinstance(results, ba.TeamGameResults)
+ results = self.settings_raw['results']
+ assert isinstance(results, ba.GameResults)
self.show_player_scores(delay=0.001,
results=results,
scale=1.2,
@@ -161,7 +147,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,
@@ -202,8 +188,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 +206,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 +245,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/multiteamjoin.py b/assets/src/ba_data/python/bastd/activity/multiteamjoin.py
index 08b10b71..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
@@ -35,7 +17,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
@@ -66,9 +48,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/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py
index 1f5a9a47..ba87a616 100644
--- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py
+++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py
@@ -1,31 +1,14 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
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
@@ -34,7 +17,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')
@@ -42,7 +25,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):
@@ -70,15 +52,13 @@ 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:
"""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
@@ -89,15 +69,17 @@ 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)
- val = results.get_team_score(p_rec.team)
+ assert isinstance(results, ba.GameResults)
+ 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.TeamGameResults)
- val = results.get_team_score_str(p_rec.team)
+ assert isinstance(results, ba.GameResults)
+ 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)
@@ -107,24 +89,22 @@ 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())
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
if p_rec[1].player is player:
return p_rec[1]
return None
# 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])
@@ -141,18 +121,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,
@@ -174,8 +154,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)
@@ -195,7 +175,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),
@@ -207,18 +187,18 @@ 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()
- 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,
- 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 8f934b63..9acc7846 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
@@ -34,18 +16,16 @@ if TYPE_CHECKING:
class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
"""Final score screen for a team series."""
- def __init__(self, settings: Dict[str, Any]):
+ # 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
@@ -53,21 +33,21 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
# pylint: disable=too-many-statements
from bastd.actor.text import Text
from bastd.actor.image import Image
- 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.ui.uiscale is ba.UIScale.LARGE:
sval = ba.Lstr(resource='pressAnyKeyButtonPlayAgainText')
else:
sval = ba.Lstr(resource='pressAnyButtonPlayAgainText')
self._show_up_next = False
self._custom_continue_message = sval
super().on_begin()
- winning_team = self.settings['winner']
+ winning_sessionteam = 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.
@@ -78,8 +58,8 @@ 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.get_name(full=True), prec))
+ (prec.player.sessionteam.customdata['score'],
+ 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():
@@ -91,7 +71,8 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
tval = 6.4
t_incr = 0.12
- always_use_first_to = get_resource('bestOfUseFirstToInstead')
+ always_use_first_to = ba.app.lang.get_resource(
+ 'bestOfUseFirstToInstead')
session = self.session
if self._is_ffa:
@@ -141,11 +122,11 @@ 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:
- 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',
@@ -172,7 +153,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
@@ -308,7 +289,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),
@@ -343,7 +324,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:
@@ -363,7 +344,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/__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/actor/background.py b/assets/src/ba_data/python/bastd/actor/background.py
index 86b0031a..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
@@ -150,8 +132,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 bf4aca77..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
@@ -26,12 +8,15 @@
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
+
+PlayerType = TypeVar('PlayerType', bound='ba.Player')
class BombFactory:
@@ -143,6 +128,19 @@ class BombFactory:
ba.Sound for a rolling bomb.
"""
+ _STORENAME = ba.storagename()
+
+ @classmethod
+ def get(cls) -> BombFactory:
+ """Get/create a shared bastd.actor.bomb.BombFactory object."""
+ activity = ba.getactivity()
+ factory = activity.customdata.get(cls._STORENAME)
+ if factory is None:
+ factory = BombFactory()
+ activity.customdata[cls._STORENAME] = 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))]
@@ -153,6 +151,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')
@@ -184,24 +183,31 @@ 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()
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)
+ # 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))
+ 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,48 +215,67 @@ 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'))
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',
- 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,27 +283,13 @@ 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()))
-
-
-# noinspection PyTypeHints
-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
- assert isinstance(factory, BombFactory)
- return factory
+ conditions=(
+ ('they_have_material', shared.player_material),
+ 'or',
+ ('they_have_material', shared.footing_material),
+ ),
+ actions=('message', 'our_node', 'at_connect', SplatMessage()),
+ )
class SplatMessage:
@@ -304,9 +315,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.
@@ -330,30 +338,31 @@ class Blast(ba.Actor):
super().__init__()
- factory = get_factory()
+ shared = SharedObjects.get()
+ factory = BombFactory.get()
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
- })
+ # Set our position a bit lower so we throw more things upward.
+ 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)
- # 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={
@@ -382,7 +391,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:
@@ -394,7 +403,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':
@@ -430,10 +439,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,
@@ -459,10 +468,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':
@@ -488,7 +497,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:
@@ -501,7 +510,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:
@@ -514,7 +523,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
@@ -556,7 +565,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,
@@ -578,7 +587,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)
@@ -594,44 +603,41 @@ 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:
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().opposingnode
+ 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=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(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):
@@ -640,7 +646,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
@@ -650,6 +656,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.
@@ -660,14 +667,16 @@ class Bomb(ba.Actor):
"""
super().__init__()
- factory = get_factory()
+ shared = SharedObjects.get()
+ factory = BombFactory.get()
if bomb_type not in ('ice', 'impact', 'land_mine', 'normal', 'sticky',
'tnt'):
- raise Exception('invalid bomb type: ' + bomb_type)
+ raise ValueError('invalid bomb type: ' + bomb_type)
self.bomb_type = bomb_type
self._exploded = False
+ self.scale = bomb_scale
self.texture_sequence: Optional[ba.Node] = None
@@ -686,34 +695,33 @@ class Bomb(ba.Actor):
self._explode_callbacks: List[Callable[[Bomb, Blast], Any]] = []
- # the player this came from
- self.source_player = source_player
+ # 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.
+ # 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
- # 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.
+ # FIXME: can we unify this and source_player?
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,
- 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, )
@@ -735,6 +743,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',
@@ -752,6 +761,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',
@@ -767,6 +777,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,
@@ -804,6 +815,7 @@ class Bomb(ba.Actor):
'position': position,
'velocity': velocity,
'model': model,
+ 'body_scale': self.scale,
'shadow_size': 0.3,
'color_texture': tex,
'sticky': sticky,
@@ -828,17 +840,23 @@ 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) -> Optional[ba.Player]:
- """Returns a ba.Player representing the source of this bomb.
-
- Be prepared for values of None or invalid Player refs."""
- return self.source_player
+ def get_source_player(
+ self, playertype: Type[PlayerType]) -> Optional[PlayerType]:
+ """Return the source-player if one exists and is the provided type."""
+ player: Any = self._source_player
+ return (player if isinstance(player, playertype) and player.exists()
+ else None)
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:
@@ -849,14 +867,14 @@ 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...
- # 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
+ node = ba.getcollision().opposingnode
+
+ # 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
(node is self.owner or
@@ -870,24 +888,22 @@ 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.get_collision_info('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()
assert self.node
- ba.playsound(get_factory().sticky_impact_sound,
+ ba.playsound(BombFactory.get().sticky_impact_sound,
2.0,
position=self.node.position)
@@ -903,26 +919,25 @@ 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,
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:
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:
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)
@@ -941,7 +956,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)
@@ -952,6 +967,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,
@@ -978,28 +994,32 @@ 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
- or self.bomb_type in ['impact', 'land_mine']):
+ 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
# 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)
# 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],
@@ -1016,12 +1036,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 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
+ # # 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/controlsguide.py b/assets/src/ba_data/python/bastd/actor/controlsguide.py
index 3b54729d..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
@@ -243,6 +225,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
@@ -264,7 +253,9 @@ 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(
+ # (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)
if touchscreen is not None:
@@ -272,7 +263,7 @@ class ControlsGuide(ba.Actor):
# 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
+ p.inputdevice for p in ba.getsession().sessionplayers
]
input_devices = [
i for i in input_devices if i and i is not touchscreen
@@ -284,8 +275,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:
@@ -325,13 +316,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().sessionplayers]
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)
@@ -368,20 +359,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)
@@ -470,8 +461,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 f9784336..417a3d46 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
@@ -26,6 +8,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
@@ -58,66 +41,82 @@ class FlagFactory:
The ba.Texture for flags.
"""
+ _STORENAME = ba.storagename()
+
def __init__(self) -> None:
"""Instantiate a 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'))),
- actions=('modify_node_collision', 'collide', False))
+ conditions=(
+ ('we_are_younger_than', 100),
+ 'and',
+ ('they_have_material', shared.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',
+ shared.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',
+ shared.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', shared.pickup_material),
+ 'or',
+ ('they_have_material', shared.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', shared.object_material),
+ 'or',
+ ('they_dont_have_material', shared.footing_material),
+ ),
actions=(('modify_part_collision', 'collide', False),
- ('modify_part_collision', 'physical', False)))
+ ('modify_part_collision', 'physical', False)),
+ )
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
+ @classmethod
+ def get(cls) -> FlagFactory:
+ """Get/create a shared FlagFactory instance."""
+ activity = ba.getactivity()
+ factory = activity.customdata.get(cls._STORENAME)
+ if factory is None:
+ factory = FlagFactory()
+ activity.customdata[cls._STORENAME] = factory
+ assert isinstance(factory, FlagFactory)
+ return factory
@dataclass
@@ -126,7 +125,7 @@ class FlagPickedUpMessage:
category: Message Classes
- Attrs:
+ Attributes:
flag
The ba.Flag that has been picked up.
@@ -139,12 +138,12 @@ class FlagPickedUpMessage:
@dataclass
-class FlagDeathMessage:
+class FlagDiedMessage:
"""A message saying a ba.Flag has died.
category: Message Classes
- Attrs:
+ Attributes:
flag
The ba.Flag that died.
@@ -158,7 +157,7 @@ class FlagDroppedMessage:
category: Message Classes
- Attrs:
+ Attributes:
flag
The ba.Flag that was dropped.
@@ -201,7 +200,8 @@ class Flag(ba.Actor):
self._initial_position: Optional[Sequence[float]] = None
self._has_moved = False
- factory = get_factory()
+ shared = SharedObjects.get()
+ factory = FlagFactory.get()
if materials is None:
materials = []
@@ -211,9 +211,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':
@@ -328,14 +327,12 @@ 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()
+ assert not self.expired
if isinstance(msg, ba.DieMessage):
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
@@ -344,24 +341,26 @@ 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)
+
+ @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/actor/image.py b/assets/src/ba_data/python/bastd/actor/image.py
index 05aff991..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
@@ -181,8 +163,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/onscreencountdown.py b/assets/src/ba_data/python/bastd/actor/onscreencountdown.py
index 59b5070c..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
@@ -79,7 +61,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 +69,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 bc65c05c..c58e87db 100644
--- a/assets/src/ba_data/python/bastd/actor/onscreentimer.py
+++ b/assets/src/ba_data/python/bastd/actor/onscreentimer.py
@@ -1,32 +1,14 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, overload
import ba
if TYPE_CHECKING:
- from typing import Optional, Union, Any
+ from typing import Optional, Union, Any, Literal
class OnScreenTimer(ba.Actor):
@@ -39,7 +21,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 +45,14 @@ 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
- ba.sharedobj('globals').connectattr('time', self.inputnode, 'time2')
+ self._starttime_ms = tval
+ self.inputnode.time1 = self._starttime_ms
+ ba.getactivity().globalsnode.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 +68,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
@@ -95,9 +78,22 @@ class OnScreenTimer(ba.Actor):
assert isinstance(endtime, int)
endtime_ms = endtime
else:
- raise Exception(f'invalid timeformat: {timeformat}')
+ 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,17 +105,22 @@ 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
if timeformat is ba.TimeFormat.MILLISECONDS:
return val_ms
- raise Exception(f'invalid timeformat: {timeformat}')
+ 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
diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py
index 82a1c0b7..b77aa8a4 100644
--- a/assets/src/ba_data/python/bastd/actor/playerspaz.py
+++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py
@@ -1,64 +1,19 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, TypeVar, overload
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, Type, Literal
-
-class PlayerSpazDeathMessage:
- """A message saying a ba.PlayerSpaz has died.
-
- category: Message Classes
-
- Attributes:
-
- spaz
- The ba.PlayerSpaz that died.
-
- 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
+PlayerType = TypeVar('PlayerType', bound=ba.Player)
+TeamType = TypeVar('TeamType', bound=ba.Team)
class PlayerSpazHurtMessage:
@@ -82,7 +37,7 @@ class PlayerSpaz(Spaz):
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)
@@ -91,10 +46,10 @@ class PlayerSpaz(Spaz):
"""
def __init__(self,
+ player: ba.Player,
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.
@@ -114,31 +69,35 @@ class PlayerSpaz(Spaz):
self.held_count = 0
self.last_player_held_by: Optional[ba.Player] = None
self._player = player
+ self._drive_player_position()
- # Grab the node for this player and wire it to follow our spaz
- # (so players' controllers know where to draw their guides, etc).
- if player:
- assert self.node
- assert player.node
- self.node.connectattr('torso_position', player.node, 'position')
+ # Overloads to tell the type system our return type based on doraise val.
- @property
- def player(self) -> ba.Player:
- """The ba.Player associated with this Spaz.
+ @overload
+ def getplayer(self,
+ playertype: Type[PlayerType],
+ doraise: Literal[False] = False) -> Optional[PlayerType]:
+ ...
- If the player no longer exists, raises an ba.PlayerNotFoundError.
- """
- if not self._player:
- raise ba.PlayerNotFoundError()
- return self._player
+ @overload
+ def getplayer(self, playertype: Type[PlayerType],
+ doraise: Literal[True]) -> PlayerType:
+ ...
- def getplayer(self) -> Optional[ba.Player]:
+ 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.
"""
- # Convert invalid references to None.
- 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,
@@ -153,41 +112,42 @@ class PlayerSpaz(Spaz):
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
# 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(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.assign_input_call('jumpPress', self.on_jump_press)
- player.assign_input_call('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.assign_input_call('pickUpPress', self.on_pickup_press)
- player.assign_input_call('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.assign_input_call('punchPress', self.on_punch_press)
- player.assign_input_call('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.assign_input_call('bombPress', self.on_bomb_press)
- player.assign_input_call('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.assign_input_call('run', self.on_run)
+ player.assigninput(intp.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(intp.FLY_PRESS, self.on_fly_press)
+ player.assigninput(intp.FLY_RELEASE, self.on_fly_release)
self._connected_to_player = player
@@ -197,13 +157,13 @@ 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.
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()
@@ -219,31 +179,37 @@ 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):
- super().handlemessage(msg) # Augment standard behavior.
+ # Augment standard behavior.
+ super().handlemessage(msg)
self.held_count += 1
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 = msg.node.source_player
- except Exception:
- picked_up_by = None
+ 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):
+ super().handlemessage(msg) # Augment standard behavior.
+
+ # Our Spaz was just moved somewhere. Explicitly update
+ # our associated player's position in case it is being used
+ # for logic (otherwise it will be out of date until next step)
+ self._drive_player_position()
+
elif isinstance(msg, ba.DieMessage):
# Report player deaths to the game.
@@ -255,6 +221,7 @@ class PlayerSpaz(Spaz):
activity = self._activity()
+ player = self.getplayer(ba.Player, False)
if not killed:
killerplayer = None
else:
@@ -277,31 +244,46 @@ class PlayerSpaz(Spaz):
# 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
- # 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():
+ if killed and activity is not None and player:
activity.handlemessage(
- PlayerSpazDeathMessage(self, killed, killerplayer,
- msg.how))
+ ba.PlayerDiedMessage(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:
- self.last_player_attacked_by = msg.source_player
+ source_player = msg.get_source_player(type(self._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) # 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)
+ return super().handlemessage(msg)
+ return None
+
+ def _drive_player_position(self) -> None:
+ """Drive our ba.Player's official position
+
+ If our position is changed explicitly, this should be called again
+ to instantly update the player position (otherwise it would be out
+ of date until the next sim step)
+ """
+ player = self._player
+ if player:
+ assert self.node
+ assert player.node
+ self.node.connectattr('torso_position', player.node, '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..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
@@ -122,8 +104,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 29f14766..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
@@ -26,6 +8,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
@@ -97,6 +80,8 @@ class PowerupBoxFactory:
that has this ba.Material applied.
"""
+ _STORENAME = ba.storagename()
+
def __init__(self) -> None:
"""Instantiate a PowerupBoxFactory.
@@ -104,6 +89,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 +116,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():
@@ -182,20 +171,16 @@ 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 Exception('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())
+ @classmethod
+ def get(cls) -> PowerupBoxFactory:
+ """Return a shared ba.PowerupBoxFactory object, creating if needed."""
+ activity = ba.getactivity()
+ if activity is None:
+ 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
@@ -228,8 +213,8 @@ class PowerupBox(ba.Actor):
"""
super().__init__()
-
- factory = get_factory()
+ shared = SharedObjects.get()
+ factory = PowerupBoxFactory.get()
self.poweruptype = poweruptype
self._powersgiven = False
@@ -252,10 +237,10 @@ class PowerupBox(ba.Actor):
elif poweruptype == 'curse':
tex = factory.tex_curse
else:
- raise Exception('invalid poweruptype: ' + str(poweruptype))
+ raise ValueError('invalid poweruptype: ' + str(poweruptype))
if len(position) != 3:
- raise Exception('expected 3 floats for position')
+ raise ValueError('expected 3 floats for position')
self.node = ba.newnode(
'prop',
@@ -270,7 +255,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.
@@ -288,12 +273,10 @@ 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 = get_factory()
+ factory = PowerupBoxFactory.get()
assert self.node
if self.poweruptype == 'health':
ba.playsound(factory.health_powerup_sound,
@@ -305,11 +288,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().opposingnode
+ node.handlemessage(
+ ba.PowerupMessage(self.poweruptype, sourcenode=self.node))
elif isinstance(msg, ba.DieMessage):
if self.node:
@@ -327,4 +308,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/respawnicon.py b/assets/src/ba_data/python/bastd/actor/respawnicon.py
index a6d91b74..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
@@ -39,19 +21,21 @@ 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 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 = player.team.customdata.get(self._MASKTEXSTORENAME)
+ if mask_tex is None:
+ mask_tex = ba.gettexture('characterIconMask')
+ player.team.customdata[self._MASKTEXSTORENAME] = mask_tex
+ assert isinstance(mask_tex, ba.Texture)
# Now find the first unused slot and use that.
index = 0
@@ -89,7 +73,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',
@@ -135,32 +119,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.get_id() % 2 == 1
+ 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']) = {}
+ icons = player.team.customdata.get(self._ICONSSTORENAME)
+ if icons is None:
+ player.team.customdata[self._ICONSSTORENAME] = 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.customdata.get(self._ICONSSTORENAME)
+ if icons is None:
+ activity.customdata[self._ICONSSTORENAME] = 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 c229ca55..54e13129 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
@@ -30,14 +12,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
@@ -53,12 +33,12 @@ class _Entry:
self._flash_timer: Optional[ba.Timer] = None
self._flash_counter: Optional[int] = None
self._flash_colors: Optional[bool] = None
- self._score: Optional[int] = None
+ self._score: Optional[float] = None
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 +132,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():
@@ -200,9 +180,11 @@ 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)
self._backing.node.position = (position[0] + self._width / 2,
position[1] - self._height / 2)
@@ -225,29 +207,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
@@ -258,15 +240,15 @@ class _Entry:
self._set_flash_colors(not self._flash_colors)
def set_value(self,
- score: int,
- max_score: int = None,
+ score: float,
+ max_score: float = None,
countdown: bool = False,
flash: bool = True,
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:
@@ -315,15 +297,26 @@ 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
- self._team_id = team.get_id()
+
+ # 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
- if scoreboard is not None:
- scoreboard.remove_team(self._team_id)
+
+ # 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 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:
@@ -332,8 +325,10 @@ class Scoreboard:
category: Gameplay Classes
"""
+ _ENTRYSTORENAME = ba.storagename('entry')
+
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.
@@ -343,7 +338,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
@@ -360,35 +355,36 @@ class Scoreboard:
def set_team_value(self,
team: ba.Team,
- score: int,
- max_score: int = None,
+ score: float,
+ max_score: float = None,
countdown: bool = False,
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 team.id not 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)
- # 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)
+ 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,
+ 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:
- 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)
+ if team.id in self._entries:
+ raise RuntimeError('Duplicate team add')
+ 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/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 96c713c4..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
@@ -28,7 +10,9 @@ 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
+from bastd.actor.spazfactory import SpazFactory
+from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import (Any, Sequence, Optional, Dict, List, Union, Callable,
@@ -55,19 +39,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:
- # noinspection PyTypeHints
- factory = activity.shared_spaz_factory = SpazFactory() # type: ignore
- assert isinstance(factory, SpazFactory)
- return factory
-
-
class Spaz(ba.Actor):
"""
Base class for various Spazzes.
@@ -109,9 +80,10 @@ class Spaz(ba.Actor):
# pylint: disable=too-many-statements
super().__init__()
+ 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
@@ -127,7 +99,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:
@@ -136,25 +108,21 @@ 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:
- pam = powerupbox.get_factory().powerup_accept_material
+ pam = PowerupBoxFactory.get().powerup_accept_material
materials.append(pam)
roller_materials.append(pam)
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,
@@ -252,7 +220,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 +241,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:
@@ -430,7 +399,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.
@@ -440,7 +409,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.
@@ -468,7 +437,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:
@@ -607,7 +576,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.
@@ -639,7 +608,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
@@ -652,7 +621,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,
@@ -687,7 +656,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:
@@ -697,8 +666,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:
@@ -725,7 +693,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 +753,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:
@@ -805,7 +773,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)
@@ -835,7 +803,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:
@@ -845,21 +813,21 @@ 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
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):
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
@@ -884,7 +852,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
@@ -927,13 +895,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)
@@ -947,7 +915,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)
@@ -1004,14 +972,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.
@@ -1070,9 +1038,9 @@ class Spaz(ba.Actor):
if self.hitpoints > 0:
# It's kinda crappy to die from impacts, so lets reduce
- # impact damage by a reasonable amount if it'll keep us alive
+ # impact damage by a reasonable amount *if* it'll keep us alive
if msg.hit_type == 'impact' and damage > self.hitpoints:
- # drop damage to whatever puts us at 10 hit points,
+ # Drop damage to whatever puts us at 10 hit points,
# or 200 less than it used to be whichever is greater
# (so it *can* still kill us if its high enough)
newdamage = max(damage - 200, self.hitpoints - 10)
@@ -1081,26 +1049,28 @@ class Spaz(ba.Actor):
# If we're holding something, drop it.
if damage > 0.0 and self.node.hold_node:
- # self.node.hold_node = ba.Node(None)
self.node.hold_node = None
self.hitpoints -= damage
self.node.hurt = 1.0 - float(
self.hitpoints) / self.hitpoints_max
+
# 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))
- # if we're frozen, shatter.. otherwise die if we hit zero
+ 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()
elif self.hitpoints <= 0:
self.node.handlemessage(
ba.DieMessage(how=ba.DeathType.IMPACT))
- # if we're dead, take a look at the smoothed damage val
+ # If we're dead, take a look at the smoothed damage value
# (which gives us a smoothed average of recent damage) and shatter
- # us if its grown high enough
+ # us if its grown high enough.
if self.hitpoints <= 0:
damage_avg = self.node.damage_smoothed * damage_scale
if damage_avg > 1000:
@@ -1119,7 +1089,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)
@@ -1141,27 +1111,27 @@ class Spaz(ba.Actor):
elif isinstance(msg, PunchHitMessage):
if not self.node:
return None
- node = ba.get_collision_info('opposing_node')
+ node = ba.getcollision().opposingnode
- # only allow one hit per node per punch
+ # Only allow one hit per node per punch.
if node and (node not in self._punched_nodes):
punch_momentum_angular = (self.node.punch_momentum_angular *
self._punch_power_scale)
punch_power = self.node.punch_power * self._punch_power_scale
- # ok here's the deal: we pass along our base velocity for use
+ # Ok here's the deal: we pass along our base velocity for use
# in the impulse damage calculations since that is a more
# predictable value than our fist velocity, which is rather
- # erratic. ...however we want to actually apply force in the
- # direction our fist is moving so it looks better.. so we still
- # pass that along as a direction ..perhaps a time-averaged
- # fist-velocity would work too?.. should try that.
+ # erratic. However, we want to actually apply force in the
+ # direction our fist is moving so it looks better. So we still
+ # pass that along as a direction. Perhaps a time-averaged
+ # fist-velocity would work too?.. perhaps should try that.
- # if its something besides another spaz, just do a muffled
- # punch sound
+ # 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)
@@ -1200,24 +1170,25 @@ 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()
+ 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).
@@ -1225,9 +1196,9 @@ class Spaz(ba.Actor):
if held and held.getnodetype() == 'flag':
return True
- # hold_body needs to be set before hold_node.
- self.node.hold_body = opposing_body
- self.node.hold_node = opposing_node
+ # Note: hold_body needs to be set before hold_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))
@@ -1279,7 +1250,8 @@ class Spaz(ba.Actor):
def _pick_up(self, node: ba.Node) -> None:
if self.node:
- self.node.hold_body = 0 # needs to be set before hold_node
+ # Note: hold_body needs to be set before hold_node.
+ self.node.hold_body = 0
self.node.hold_node = node
def set_land_mine_count(self, count: int) -> None:
@@ -1289,7 +1261,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 = ''
@@ -1316,7 +1288,7 @@ class Spaz(ba.Actor):
self.shattered = True
assert self.node
if self.frozen:
- # momentary flash of light
+ # Momentary flash of light.
light = ba.newnode('light',
attrs={
'position': self.node.position,
@@ -1332,7 +1304,8 @@ class Spaz(ba.Actor):
0.3: 0
})
ba.timer(0.3, light.delete)
- # emit ice chunks..
+
+ # Emit ice chunks.
ba.emitfx(position=self.node.position,
velocity=self.node.velocity,
count=int(random.random() * 10.0 + 10.0),
@@ -1345,11 +1318,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())
@@ -1367,23 +1340,23 @@ 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)
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
- raise Exception()
+ return factory.tex_impact_bombs
+ raise ValueError('invalid bomb type')
def _flash_billboard(self, tex: ba.Texture) -> None:
assert self.node
@@ -1398,8 +1371,8 @@ class Spaz(ba.Actor):
def set_bomb_count(self, count: int) -> None:
"""Sets the number of bombs this Spaz has."""
- # we cant just set bomb_count cuz some bombs may be laid currently
- # so we have to do a relative diff based on max
+ # We can't just set bomb_count because some bombs may be laid currently
+ # so we have to do a relative diff based on max.
diff = count - self._max_bomb_count
self._max_bomb_count += diff
self.bomb_count += diff
@@ -1407,35 +1380,35 @@ 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
def _gloves_wear_off(self) -> None:
- if self._demo_mode: # preserve old behavior
+ if self._demo_mode: # Preserve old behavior.
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
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
@@ -1448,6 +1421,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/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 1b5e4b8c..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
@@ -28,7 +10,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
@@ -49,27 +31,27 @@ 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
-class SpazBotDeathMessage:
+class SpazBotDiedMessage:
"""A message saying a ba.SpazBot has died.
category: Message Classes
Attributes:
- badguy
+ spazbot
The ba.SpazBot that was killed.
killerplayer
@@ -79,15 +61,15 @@ class SpazBotDeathMessage:
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
-class SpazBot(basespaz.Spaz):
+class SpazBot(Spaz):
"""A really dumb AI version of ba.Spaz.
category: Bot Classes
@@ -98,7 +80,7 @@ class SpazBot(basespaz.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
@@ -127,13 +109,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
@@ -236,11 +217,7 @@ class SpazBot(basespaz.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
@@ -281,11 +258,8 @@ class SpazBot(basespaz.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
@@ -503,7 +477,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.
@@ -511,8 +485,7 @@ class SpazBot(basespaz.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):
@@ -534,8 +507,8 @@ class SpazBot(basespaz.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:
@@ -570,13 +543,14 @@ class SpazBot(basespaz.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.
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)
@@ -894,7 +868,7 @@ class ExplodeyBotShielded(ExplodeyBot):
points_mult = 5
-class BotSet:
+class SpazBotSet:
"""A container/controller for one or more ba.SpazBots.
category: Bot Classes
@@ -963,16 +937,14 @@ 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
])
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
@@ -980,14 +952,18 @@ 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:
+ # 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, 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)))
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)
@@ -997,8 +973,8 @@ class BotSet:
"""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)
- if activity is None or activity.is_expired():
+ activity = ba.getactivity(doraise=False)
+ 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/actor/spazfactory.py b/assets/src/ba_data/python/bastd/actor/spazfactory.py
index ac7e8983..7363ec43 100644
--- a/assets/src/ba_data/python/bastd/actor/spazfactory.py
+++ b/assets/src/ba_data/python/bastd/actor/spazfactory.py
@@ -1,32 +1,14 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
from typing import TYPE_CHECKING
-import _ba
import ba
-from bastd.actor import spaz as basespaz
+from bastd.gameutils import SharedObjects
+import _ba
if TYPE_CHECKING:
from typing import Any, Dict
@@ -95,12 +77,21 @@ 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'))
self.impact_sounds_hard = (ba.getsound('impactHard'),
@@ -123,14 +114,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 +131,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 +171,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(
@@ -242,3 +253,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/actor/text.py b/assets/src/ba_data/python/bastd/actor/text.py
index 0afccf5b..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
@@ -229,8 +211,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..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
@@ -103,8 +85,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..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
@@ -171,8 +153,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/assets/src/ba_data/python/bastd/appdelegate.py b/assets/src/ba_data/python/bastd/appdelegate.py
index 91e24ac0..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
@@ -32,17 +14,18 @@ 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]]],
- Any]) -> None:
+ sessiontype: Type[ba.Session], settings: Optional[dict],
+ completion_call: Callable[[Optional[dict]], Any]) -> None:
"""(internal)"""
# 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, sessionclass, config,
- 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/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/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py
index fd60dc01..44dc8ca0 100644
--- a/assets/src/ba_data/python/bastd/game/assault.py
+++ b/assets/src/ba_data/python/bastd/game/assault.py
@@ -1,27 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@@ -29,23 +11,65 @@ import random
from typing import TYPE_CHECKING
import ba
-from bastd.actor import playerspaz
+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, Tuple, Sequence, Union
+ from typing import Any, Type, List, Dict, Sequence, Union
+
+
+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, 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):
+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.'
+ 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
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -55,110 +79,93 @@ class AssaultGame(ba.TeamGameActivity):
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})] # yapf: disable
-
- def __init__(self, settings: Dict[str, Any]):
- from bastd.actor.scoreboard import Scoreboard
+ def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
- if self.settings['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['Score to Win'] == 1:
+ if self._score_to_win == 1:
return 'Touch the enemy flag.'
- return ('Touch the enemy flag ${ARG1} times.',
- self.settings['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['Score to Win'] == 1:
+ def get_instance_description_short(self) -> Union[str, Sequence]:
+ if self._score_to_win == 1:
return 'touch 1 flag'
- return 'touch ${ARG1} flags', self.settings['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['Epic Mode']
- else ba.MusicType.FORWARD_MARCH)
- super().on_transition_in()
+ def create_team(self, sessionteam: ba.SessionTeam) -> Team:
+ shared = SharedObjects.get()
+ 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
+ })
+ Flag.project_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', shared.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['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.get_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.get_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.get_id()]]
- })
def handlemessage(self, msg: Any) -> Any:
- if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
+ if isinstance(msg, ba.PlayerDiedMessage):
super().handlemessage(msg) # Augment standard.
- self.respawn_player(msg.spaz.player)
+ self.respawn_player(msg.getplayer(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,16 +173,14 @@ class AssaultGame(ba.TeamGameActivity):
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:
-
- # 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.PlayerSpaz):
+ def _handle_base_collide(self, team: Team) -> None:
+ try:
+ player = ba.getcollision().opposingnode.getdelegate(
+ PlayerSpaz, True).getplayer(Player, True)
+ except ba.NotFoundError:
return
- player = actor.getplayer()
- if not player or not player.is_alive():
+
+ if not player.is_alive():
return
# If its another team's player, they scored.
@@ -193,24 +198,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,
@@ -234,19 +237,18 @@ class AssaultGame(ba.TeamGameActivity):
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['Score to Win']):
+ if player_team.score >= self._score_to_win:
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.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['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 68fe9b87..638d2d3b 100644
--- a/assets/src/ba_data/python/bastd/game/capturetheflag.py
+++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py
@@ -1,46 +1,33 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (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
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
+from bastd.actor.flag import (FlagFactory, Flag, FlagPickedUpMessage,
+ FlagDroppedMessage, FlagDiedMessage)
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):
- """Special flag type for ctf games."""
+class CTFFlag(Flag):
+ """Special flag type for CTF games."""
- def __init__(self, team: ba.Team):
- super().__init__(materials=[team.gamedata['flagmaterial']],
- position=team.gamedata['base_pos'],
+ activity: CaptureTheFlagGame
+
+ 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,42 +39,97 @@ 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
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.touch_return_time = float(
- self.activity.settings['Flag Touch Return Time'])
+ self.time_out_respawn_time = int(self.activity.flag_idle_return_time)
+ self.touch_return_time = float(self.activity.flag_touch_return_time)
@property
- def team(self) -> ba.Team:
- """return the flag's team."""
+ def team(self) -> 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."""
- if not node:
- return None
- delegate = node.getdelegate()
- return delegate if isinstance(delegate, CTFFlag) else None
+
+class Player(ba.Player['Team']):
+ """Our player type for this game."""
+
+ def __init__(self) -> None:
+ self.touching_own_flag = 0
+
+
+class Team(ba.Team[Player]):
+ """Our team type for this game."""
+
+ 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
-class CaptureTheFlagGame(ba.TeamGameActivity):
+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.'
+ 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
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -97,80 +139,58 @@ class CaptureTheFlagGame(ba.TeamGameActivity):
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})] # yapf: disable
-
- def __init__(self, settings: Dict[str, Any]):
- from bastd.actor.scoreboard import Scoreboard
+ def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
- if self.settings['Epic Mode']:
- self.slow_motion = True
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'])
+ self._epic_mode = bool(settings['Epic Mode'])
+ 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'])
+
+ # Base class overrides.
+ self.slow_motion = self._epic_mode
+ self.default_music = (ba.MusicType.EPIC if self._epic_mode else
+ ba.MusicType.FLAG_CATCHER)
def get_instance_description(self) -> Union[str, Sequence]:
- if self.settings['Score to Win'] == 1:
+ if self._score_to_win == 1:
return 'Steal the enemy flag.'
- return ('Steal the enemy flag ${ARG1} times.',
- self.settings['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['Score to Win'] == 1:
+ def get_instance_description_short(self) -> Union[str, Sequence]:
+ if self._score_to_win == 1:
return 'return 1 flag'
- return 'return ${ARG1} flags', self.settings['Score to Win']
+ return 'return ${ARG1} flags', self._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)
- super().on_transition_in()
+ def create_team(self, sessionteam: ba.SessionTeam) -> Team:
- 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()))
+ # Create our team instance and its initial values.
- self.project_flag_stand(team.gamedata['base_pos'])
+ base_pos = self.map.get_flag_position(sessionteam.id)
+ Flag.project_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]),
@@ -179,73 +199,85 @@ 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_touching_own_flag(team, True)),
+ ('call', 'at_disconnect',
+ lambda: self._handle_touching_own_flag(team, False)),
+ ))
# 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',
- stdflag.get_factory().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))))
+ 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)),
+ ))
+ 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()
def on_begin(self) -> None:
super().on_begin()
- self.setup_standard_time_limit(self.settings['Time Limit'])
+ self.setup_standard_time_limit(self._time_limit)
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:
- node = ba.get_collision_info('opposing_node')
- assert isinstance(node, (ba.Node, type(None)))
- flag = CTFFlag.from_node(node)
- if not flag:
- print('Unable to get flag in _handle_flag_entered_base')
+ def _handle_flag_entered_base(self, team: Team) -> None:
+ 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:
- 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:
@@ -261,7 +293,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',
@@ -285,10 +317,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()
@@ -306,153 +338,143 @@ 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()
- # Have teammates celebrate
+ # Have teammates celebrate.
for player in team.players:
if player.actor:
player.actor.handlemessage(ba.CelebrateMessage(2.0))
# 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['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._score_to_win:
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.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:
+ try:
+ 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.
- 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.touch_return_time -= 0.1
- if flag.counter:
- flag.counter.text = '%.1f' % flag.touch_return_time
- flag.counter.color = (1, 1, 0, 1)
- flag.counter.scale = 0.02
+ flag = team.flag
+ 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: 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:
- return_score = 10 + 5 * int(
- self.settings['Flag Touch Return Time'])
+ if player.touching_own_flag > 0:
+ return_score = 10 + 5 * int(self.flag_touch_return_time)
self.stats.player_scored(player,
return_score,
screenmessage=False)
- @staticmethod
- def _player_from_node(node: Optional[ba.Node]) -> Optional[ba.Player]:
- """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()
+ def _handle_touching_own_flag(self, team: Team, connecting: bool) -> None:
+ """Called when a player touches or stops touching their own team flag.
- def _handle_hit_own_flag(self, team: ba.Team, val: int) -> None:
+ 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
- """
- srcnode = ba.get_collision_info('source_node')
- assert isinstance(srcnode, (ba.Node, type(None)))
- player = self._player_from_node(srcnode)
+ 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.gamedata['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.settings['Flag Touch Return Time']) <= 0.0:
- if (not team.gamedata['home_flag_at_base']
- and team.gamedata['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.get_collision_info('opposing_node')
- if node:
- self._award_players_touching_own_flag(team)
- node.handlemessage(ba.DieMessage())
+ if float(self.flag_touch_return_time) <= 0.0:
+ assert team.flag is not None
+ if (connecting and not team.home_flag_at_base
+ and team.flag.held_count == 0):
+ self._award_players_touching_own_flag(team)
+ ba.getcollision().opposingnode.handlemessage(ba.DieMessage())
# 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(
+ if connecting:
+ 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:
- ba.print_error(
- "CTF: flag_return_touches < 0; this shouldn't happen.")
+ 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')
- 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
@@ -460,22 +482,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 = ba.TeamGameActivity.spawn_player_spaz(self, *args, **keywds)
- 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']
+ spaz = super().spawn_player_spaz(player, position, angle)
+ player = spaz.getplayer(Player, True)
+ 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).
@@ -495,26 +516,36 @@ 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._scoreboard.set_team_value(team, team.score,
+ self._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)
- elif isinstance(msg, stdflag.FlagDeathMessage):
+
+ if isinstance(msg, ba.PlayerDiedMessage):
+ 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, 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()
+ 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()
- 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
+
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 32a5613b..465dec97 100644
--- a/assets/src/ba_data/python/bastd/game/chosenone.py
+++ b/assets/src/ba_data/python/bastd/game/chosenone.py
@@ -1,101 +1,93 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (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
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
+from bastd.actor.scoreboard import Scoreboard
+from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
- from typing import (Any, Type, List, Dict, Tuple, Optional, Sequence,
- Union)
+ from typing import Any, Type, List, Dict, Optional, Sequence, Union
+
+
+class Player(ba.Player['Team']):
+ """Our player type for this game."""
+
+ def __init__(self) -> None:
+ self.chosen_light: Optional[ba.NodeActor] = None
+
+
+class Team(ba.Team[Player]):
+ """Our team type for this game."""
+
+ def __init__(self, time_remaining: int) -> None:
+ self.time_remaining = time_remaining
# ba_meta export game
-class ChosenOneGame(ba.TeamGameActivity):
+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
kill you and become the chosen one themselves.
"""
- @classmethod
- def get_name(cls) -> str:
- return 'Chosen One'
-
- @classmethod
- def get_score_info(cls) -> Dict[str, Any]:
- return {'score_name': '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.')
+ 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),
+ ]
+ scoreconfig = ba.ScoreConfig(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
+ def __init__(self, settings: dict):
super().__init__(settings)
- if self.settings['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'),
@@ -111,44 +103,58 @@ class ChosenOneGame(ba.TeamGameActivity):
}
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['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['Chosen One Time']
+ def on_team_join(self, team: Team) -> None:
self._update_scoreboard()
- def on_player_leave(self, player: ba.Player) -> None:
- ba.TeamGameActivity.on_player_leave(self, player)
+ 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['Time Limit'])
+ 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)
- 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
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',
+ shared.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={
@@ -159,7 +165,8 @@ class ChosenOneGame(ba.TeamGameActivity):
'materials': [mat]
})
- def _get_chosen_one_player(self) -> Optional[ba.Player]:
+ 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
@@ -168,12 +175,15 @@ class ChosenOneGame(ba.TeamGameActivity):
# If we have a chosen one, ignore these.
if self._get_chosen_one_player() is not None:
return
+
+ # Attempt to get a Player controlling a Spaz that we hit.
try:
- player = (ba.get_collision_info(
- 'opposing_node').getdelegate().getplayer())
- except Exception:
+ player = ba.getcollision().opposingnode.getdelegate(
+ PlayerSpaz, True).getplayer(Player, True)
+ except ba.NotFoundError:
return
- if player is not None and player.is_alive():
+
+ if player.is_alive():
self._set_chosen_one_player(player)
def _flash_flag_spawn(self) -> None:
@@ -205,29 +215,24 @@ class ChosenOneGame(ba.TeamGameActivity):
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:
@@ -240,91 +245,84 @@ class ChosenOneGame(ba.TeamGameActivity):
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.settings['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:
+ 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
+ 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['Chosen One Gets Shield']:
- player.actor.handlemessage(
- ba.PowerupMessage('shield'))
- if self.settings['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, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
- player = msg.spaz.player
+ player = msg.getplayer(Player)
if player is self._get_chosen_one_player():
- killerplayer = msg.killerplayer
+ 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)
@@ -335,6 +333,6 @@ 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'],
+ team.time_remaining,
+ self._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..b2404b8e 100644
--- a/assets/src/ba_data/python/bastd/game/conquest.py
+++ b/assets/src/ba_data/python/bastd/game/conquest.py
@@ -1,27 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@@ -30,11 +12,13 @@ from typing import TYPE_CHECKING
import ba
from bastd.actor.flag import Flag
-from bastd.actor.playerspaz import PlayerSpazDeathMessage
+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, Tuple, Dict, Sequence,
- Union)
+ from typing import Any, Optional, Type, List, Dict, Sequence, Union
+ from bastd.actor.respawnicon import RespawnIcon
class ConquestFlag(Flag):
@@ -42,31 +26,83 @@ 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."""
+
+ # 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.customdata.get('respawn_timer', None)
+
+ @respawn_timer.setter
+ def respawn_timer(self, value: Optional[ba.Timer]) -> None:
+ self.customdata['respawn_timer'] = value
+
+ @property
+ def respawn_icon(self) -> Optional[RespawnIcon]:
+ """Type safe access to standard respawn icon."""
+ return self.customdata.get('respawn_icon', None)
+
+ @respawn_icon.setter
+ def respawn_icon(self, value: Optional[RespawnIcon]) -> None:
+ self.customdata['respawn_icon'] = value
+
+
+class Team(ba.Team[Player]):
+ """Our team type for this game."""
+
+ def __init__(self) -> None:
+ self.flags_held = 0
+
+
# ba_meta export game
-class ConquestGame(ba.TeamGameActivity):
+class ConquestGame(ba.TeamGameActivity[Player, 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.'
+ 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
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -76,72 +112,50 @@ class ConquestGame(ba.TeamGameActivity):
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
+ def __init__(self, settings: dict):
super().__init__(settings)
- if self.settings['Epic Mode']:
- self.slow_motion = True
+ shared = SharedObjects.get()
self._scoreboard = Scoreboard()
self._score_sound = ba.getsound('score')
self._swipsound = ba.getsound('swip')
self._extraflagmat = ba.Material()
self._flags: List[ConquestFlag] = []
+ 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.GRAND_ROMP)
# 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')),
- actions=(('modify_part_collision', 'collide', True),
- ('call', 'at_connect', self._handle_flag_player_collide)))
+ conditions=('they_have_material', shared.player_material),
+ 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)
- 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:
- self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
- else 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:
- player.gamedata['respawn_timer'] = None
+ def on_player_join(self, player: Player) -> None:
+ player.respawn_timer = None
# Only spawn if this player's team has a flag currently.
- if player.team.gamedata['flags_held'] > 0:
+ if player.team.flags_held > 0:
self.spawn_player(player)
def on_begin(self) -> None:
super().on_begin()
- self.setup_standard_time_limit(self.settings['Time Limit'])
+ self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops()
# Set up flags with marker lights.
@@ -151,8 +165,7 @@ class ConquestGame(ba.TeamGameActivity):
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={
@@ -182,27 +195,27 @@ class ConquestGame(ba.TeamGameActivity):
def _update_scores(self) -> None:
for team in self.teams:
- team.gamedata['flags_held'] = 0
+ team.flags_held = 0
for flag in self._flags:
if flag.team is not None:
- flag.team.gamedata['flags_held'] += 1
+ flag.team.flags_held += 1
for team in self.teams:
# If a team finds themselves with no flags, cancel all
# outstanding spawn-timers.
- if team.gamedata['flags_held'] == 0:
+ if team.flags_held == 0:
for player in team.players:
- player.gamedata['respawn_timer'] = None
- player.gamedata['respawn_icon'] = None
- if team.gamedata['flags_held'] == len(self._flags):
+ player.respawn_timer = None
+ player.respawn_icon = None
+ if team.flags_held == len(self._flags):
self.end_game()
- self._scoreboard.set_team_value(team, team.gamedata['flags_held'],
+ self._scoreboard.set_team_value(team, team.flags_held,
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.gamedata['flags_held'])
+ results.set_team_score(team, team.flags_held)
self.end(results=results)
def _flash_flag(self, flag: ConquestFlag, length: float = 1.0) -> None:
@@ -218,15 +231,14 @@ class ConquestGame(ba.TeamGameActivity):
ba.timer(length, light.delete)
def _handle_flag_player_collide(self) -> None:
- flagnode, playernode = ba.get_collision_info('source_node',
- 'opposing_node')
+ collision = ba.getcollision()
try:
- player = playernode.getdelegate().getplayer()
- flag = flagnode.getdelegate()
- except Exception:
- return # Player may have left and his body hit the flag.
- assert isinstance(player, ba.Player)
- assert isinstance(flag, ConquestFlag)
+ flag = collision.sourcenode.getdelegate(ConquestFlag, True)
+ player = collision.opposingnode.getdelegate(PlayerSpaz,
+ True).getplayer(
+ Player, True)
+ except ba.NotFoundError:
+ return
assert flag.light
if flag.team is not player.team:
@@ -244,30 +256,30 @@ class ConquestGame(ba.TeamGameActivity):
if (otherplayer.team is flag.team
and otherplayer.actor is not None
and not otherplayer.is_alive()
- and otherplayer.gamedata['respawn_timer'] is None):
+ and otherplayer.respawn_timer is None):
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.spaz.player
- if player.team.gamedata['flags_held'] > 0:
+ player = msg.getplayer(Player)
+ if player.team.flags_held > 0:
self.respawn_player(player)
else:
- player.gamedata['respawn_timer'] = None
+ player.respawn_timer = None
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 a37e21ee..f91c7aff 100644
--- a/assets/src/ba_data/python/bastd/game/deathmatch.py
+++ b/assets/src/ba_data/python/bastd/game/deathmatch.py
@@ -1,50 +1,89 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (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
import ba
-from bastd.actor import playerspaz
-from bastd.actor import spaz as stdspaz
+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
+ from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional
+
+
+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:
+ self.score = 0
# ba_meta export game
-class DeathMatchGame(ba.TeamGameActivity):
+class DeathMatchGame(ba.TeamGameActivity[Player, 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.'
+ 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
+ # free-for-all it subtracts from your own score. By default we clamp
+ # this at zero to benefit new players, but pro players might like to
+ # 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(
+ ba.BoolSetting('Allow Negative Scores', default=False))
+
+ return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -55,154 +94,106 @@ class DeathMatchGame(ba.TeamGameActivity):
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
return ba.getmaps('melee')
- @classmethod
- def get_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
- })
- ] # 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
- # this at zero to benefit new players, but pro players might like to
- # 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}))
-
- return settings
-
- def __init__(self, settings: Dict[str, Any]):
- from bastd.actor.scoreboard import Scoreboard
+ def __init__(self, settings: dict):
super().__init__(settings)
- if self.settings['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._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
+ 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
- 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:
- self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
- else ba.MusicType.TO_THE_DEATH)
- 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()
def on_begin(self) -> None:
super().on_begin()
- self.setup_standard_time_limit(self.settings['Time Limit'])
+ self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops()
- if self.teams:
- self._score_to_win = (
- self.settings['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']
+
+ # 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.spaz.player
+ player = msg.getplayer(Player)
self.respawn_player(player)
- killer = msg.killerplayer
+ killer = msg.getkillerplayer(Player)
if killer is None:
- return
+ return None
# Handle team-kills.
if killer.team is 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['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:
- super().handlemessage(msg)
+ return super().handlemessage(msg)
+ return None
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()
+ results = ba.GameResults()
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 514e8f10..2c5b9b02 100644
--- a/assets/src/ba_data/python/bastd/game/easteregghunt.py
+++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py
@@ -1,27 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@@ -29,30 +11,41 @@ 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 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
+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."""
+
+ def __init__(self) -> None:
+ self.score = 0
+
+
# ba_meta export game
-class EasterEggHuntGame(ba.TeamGameActivity):
+class EasterEggHuntGame(ba.TeamGameActivity[Player, 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) -> Dict[str, Any]:
- return {'score_name': 'Score', 'score_type': 'points'}
-
- @classmethod
- def get_description(cls, sessiontype: Type[ba.Session]) -> str:
- return 'Gather eggs!'
+ name = 'Easter Egg Hunt'
+ description = 'Gather eggs!'
+ 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
@@ -66,15 +59,9 @@ class EasterEggHuntGame(ba.TeamGameActivity):
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
+ def __init__(self, settings: dict):
super().__init__(settings)
+ shared = SharedObjects.get()
self._last_player_death_time = None
self._scoreboard = Scoreboard()
self.egg_model = ba.getmodel('egg')
@@ -86,22 +73,17 @@ class EasterEggHuntGame(ba.TeamGameActivity):
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
self._countdown: Optional[OnScreenCountdown] = None
- self._bots: Optional[spazbot.BotSet] = None
+ self._bots: Optional[SpazBotSet] = 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:
+ # 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()
@@ -119,69 +101,62 @@ class EasterEggHuntGame(ba.TeamGameActivity):
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 = SpazBotSet()
# 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():
- 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.PlayerSpaz)
- player = (spaz.getplayer()
- if hasattr(spaz, 'getplayer') else None)
- if player and egg:
- player.team.gamedata['score'] += 1
+ if self.has_ended():
+ return
+ collision = ba.getcollision()
- # 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)
+ # 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 ba.NotFoundError:
+ return
- # 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())
+ 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)
+
+ # 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.
@@ -197,8 +172,8 @@ class EasterEggHuntGame(ba.TeamGameActivity):
# 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)))
@@ -207,29 +182,23 @@ class EasterEggHuntGame(ba.TeamGameActivity):
def handlemessage(self, msg: Any) -> Any:
# Respawn dead players.
- if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
- from bastd.actor import respawnicon
-
+ if isinstance(msg, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
- player = msg.spaz.getplayer()
- if not player:
- return
- self.stats.player_was_killed(player)
# 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 = msg.getplayer(Player)
+ 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.gamedata['respawn_icon'] = respawnicon.RespawnIcon(
- player, respawn_time)
+ player.respawn_icon = RespawnIcon(player, respawn_time)
# Whenever our evil bunny dies, respawn him and spew some eggs.
- elif isinstance(msg, spazbot.SpazBotDeathMessage):
+ 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(
@@ -238,16 +207,17 @@ class EasterEggHuntGame(ba.TeamGameActivity):
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:
- 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()
+ results = ba.GameResults()
for team in self.teams:
- results.set_team_score(team, team.gamedata['score'])
+ results.set_team_score(team, team.score)
self.end(results)
@@ -258,12 +228,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={
@@ -272,7 +243,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,
diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py
index 4d53150c..061ff0b4 100644
--- a/assets/src/ba_data/python/bastd/game/elimination.py
+++ b/assets/src/ba_data/python/bastd/game/elimination.py
@@ -1,35 +1,17 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (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
import ba
-from bastd.actor import playerspaz
-from bastd.actor import spaz
+from bastd.actor.spazfactory import SpazFactory
+from bastd.actor.scoreboard import Scoreboard
if TYPE_CHECKING:
from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional,
@@ -40,7 +22,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,
@@ -75,7 +57,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',
@@ -117,7 +99,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,30 +140,86 @@ 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)
+ def handlemessage(self, msg: Any) -> Any:
+ if isinstance(msg, ba.DieMessage):
+ self.node.delete()
+ return None
+ return super().handlemessage(msg)
+
+
+class Player(ba.Player['Team']):
+ """Our player type for this game."""
+
+ def __init__(self) -> None:
+ self.lives = 0
+ self.icons: List[Icon] = []
+
+
+class Team(ba.Team[Player]):
+ """Our team type for this game."""
+
+ def __init__(self) -> None:
+ self.survival_seconds: Optional[int] = None
+ self.spawn_order: List[Player] = []
+
# ba_meta export game
-class EliminationGame(ba.TeamGameActivity):
+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.'
+ 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_score_info(cls) -> Dict[str, Any]:
- return {
- 'score_name': 'Survived',
- 'score_type': 'seconds',
- 'none_is_winner': True
- }
-
- @classmethod
- def get_description(cls, sessiontype: Type[ba.Session]) -> str:
- return 'Last remaining alive wins.'
+ 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(ba.BoolSetting('Solo Mode', default=False))
+ settings.append(
+ ba.BoolSetting('Balance Total Lives', default=False))
+ return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -192,258 +230,69 @@ class EliminationGame(ba.TeamGameActivity):
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
return ba.getmaps('melee')
- @classmethod
- def get_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})] # yapf: disable
-
- if issubclass(sessiontype, ba.DualTeamSession):
- settings.append(('Solo Mode', {'default': False}))
- settings.append(('Balance Total Lives', {'default': False}))
-
- return settings
-
- def __init__(self, settings: Dict[str, Any]):
- from bastd.actor.scoreboard import Scoreboard
+ def __init__(self, settings: dict):
super().__init__(settings)
- if self.settings['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:
+ 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(
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'
- def on_transition_in(self) -> None:
- self.default_music = (ba.MusicType.EPIC if self.settings['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))
+ # 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
+ ba.screenmessage(
+ ba.Lstr(resource='playerDelayedJoinText',
+ subs=[('${PLAYER}', player.getname(full=True))]),
+ color=(0, 1, 0),
+ )
return
- player.gamedata['lives'] = self.settings['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 _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:
- if not player.is_alive():
- self.spawn_player(player)
- break
-
- def _update_icons(self) -> None:
- # pylint: disable=too-many-branches
-
- # In free-for-all mode, everyone is just lined up along the bottom.
- if isinstance(self.session, ba.FreeForAllSession):
- count = len(self.teams)
- x_offs = 85
- xval = x_offs * (count - 1) * -0.5
- for team in self.teams:
- if len(team.players) == 1:
- player = team.players[0]
- for icon in player.gamedata['icons']:
- icon.set_position_and_scale((xval, 30), 0.7)
- icon.update_for_lives()
- xval += x_offs
-
- # In teams mode we split up teams.
- else:
- if self._solo_mode:
- # First off, clear out all icons.
- for player in self.players:
- player.gamedata['icons'] = []
-
- # Now for each team, cycle through our available players
- # adding icons.
- for team in self.teams:
- if team.get_id() == 0:
- xval = -60
- x_offs = -78
- else:
- xval = 60
- x_offs = 78
- is_first = True
- test_lives = 1
- while True:
- players_with_lives = [
- p for p in team.gamedata['spawn_order']
- if p and p.gamedata['lives'] >= test_lives
- ]
- if not players_with_lives:
- break
- for player in players_with_lives:
- player.gamedata['icons'].append(
- Icon(player,
- position=(xval, (40 if is_first else 25)),
- scale=1.0 if is_first else 0.5,
- name_maxwidth=130 if is_first else 75,
- name_scale=0.8 if is_first else 1.0,
- flatness=0.0 if is_first else 1.0,
- shadow=0.5 if is_first else 1.0,
- show_death=is_first,
- show_lives=False))
- xval += x_offs * (0.8 if is_first else 0.56)
- is_first = False
- test_lives += 1
- # Non-solo mode.
- else:
- for team in self.teams:
- if team.get_id() == 0:
- xval = -50
- x_offs = -85
- else:
- xval = 50
- x_offs = 85
- for player in team.players:
- for icon in player.gamedata['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]:
- del player # Unused.
-
- # In solo-mode, if there's an existing live player on the map, spawn at
- # whichever spot is farthest from them (keeps the action spread out).
- if self._solo_mode:
- living_player = None
- living_player_pos = None
- for team in self.teams:
- for tplayer in team.players:
- if tplayer.is_alive():
- assert tplayer.node
- ppos = tplayer.node.position
- living_player = tplayer
- living_player_pos = ppos
- break
- if living_player:
- assert living_player_pos is not None
- 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()))
- points.append(
- ((start_pos - player_pos).length(), start_pos))
- # Hmm.. we need to sorting vectors too?
- points.sort(key=lambda x: x[0])
- return points[-1][1]
- return None
-
- def spawn_player(self, player: ba.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']:
- icon.handle_player_spawned()
- return actor
-
- def _print_lives(self, player: ba.Player) -> None:
- from bastd.actor import popuptext
- assert player # Shouldn't be passing invalid refs around.
- if not player or not player.is_alive() or not player.node:
- return
-
- popuptext.PopupText('x' + str(player.gamedata['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:
- ba.TeamGameActivity.on_player_leave(self, player)
- player.gamedata['icons'] = None
-
- # Remove us from spawn-order.
- if self._solo_mode:
- if player in player.team.gamedata['spawn_order']:
- player.team.gamedata['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['Time Limit'])
+ 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(
@@ -464,8 +313,8 @@ 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.teams[0].players and self.teams[1].players):
+ 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]
@@ -474,9 +323,9 @@ class EliminationGame(ba.TeamGameActivity):
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
+ 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()
@@ -485,39 +334,188 @@ class EliminationGame(ba.TeamGameActivity):
# 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 _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.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
+
+ def _update_icons(self) -> None:
+ # pylint: disable=too-many-branches
+
+ # In free-for-all mode, everyone is just lined up along the bottom.
+ if isinstance(self.session, ba.FreeForAllSession):
+ count = len(self.teams)
+ x_offs = 85
+ xval = x_offs * (count - 1) * -0.5
+ for team in self.teams:
+ if len(team.players) == 1:
+ player = team.players[0]
+ for icon in player.icons:
+ icon.set_position_and_scale((xval, 30), 0.7)
+ icon.update_for_lives()
+ xval += x_offs
+
+ # In teams mode we split up teams.
+ else:
+ if self._solo_mode:
+ # First off, clear out all icons.
+ for player in self.players:
+ player.icons = []
+
+ # Now for each team, cycle through our available players
+ # adding icons.
+ for team in self.teams:
+ if team.id == 0:
+ xval = -60
+ x_offs = -78
+ else:
+ xval = 60
+ x_offs = 78
+ is_first = True
+ test_lives = 1
+ while True:
+ players_with_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.icons.append(
+ Icon(player,
+ position=(xval, (40 if is_first else 25)),
+ scale=1.0 if is_first else 0.5,
+ name_maxwidth=130 if is_first else 75,
+ name_scale=0.8 if is_first else 1.0,
+ flatness=0.0 if is_first else 1.0,
+ shadow=0.5 if is_first else 1.0,
+ show_death=is_first,
+ show_lives=False))
+ xval += x_offs * (0.8 if is_first else 0.56)
+ is_first = False
+ test_lives += 1
+ # Non-solo mode.
+ else:
+ for team in self.teams:
+ if team.id == 0:
+ xval = -50
+ x_offs = -85
+ else:
+ xval = 50
+ x_offs = 85
+ for player in team.players:
+ 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: Player) -> Optional[ba.Vec3]:
+ del player # Unused.
+
+ # In solo-mode, if there's an existing live player on the map, spawn at
+ # whichever spot is farthest from them (keeps the action spread out).
+ if self._solo_mode:
+ living_player = None
+ living_player_pos = None
+ for team in self.teams:
+ for tplayer in team.players:
+ if tplayer.is_alive():
+ assert tplayer.node
+ ppos = tplayer.node.position
+ living_player = tplayer
+ living_player_pos = ppos
+ break
+ if living_player:
+ assert living_player_pos is not None
+ 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.id))
+ points.append(
+ ((start_pos - player_pos).length(), start_pos))
+ # Hmm.. we need to sorting vectors too?
+ points.sort(key=lambda x: x[0])
+ return points[-1][1]
+ return None
+
+ 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.icons:
+ icon.handle_player_spawned()
+ return actor
+
+ def _print_lives(self, player: Player) -> None:
+ from bastd.actor import popuptext
+
+ # 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.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: Player) -> None:
+ super().on_player_leave(player)
+ player.icons = []
+
+ # Remove us from spawn-order.
+ if self._solo_mode:
+ 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 _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):
+ if isinstance(msg, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
- player = msg.spaz.player
+ player: Player = msg.getplayer(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:
- ba.playsound(spaz.get_factory().single_player_death_sound)
+ if self._solo_mode or player.lives == 0:
+ ba.playsound(SpazFactory.get().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:
@@ -525,8 +523,8 @@ class EliminationGame(ba.TeamGameActivity):
# 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:
@@ -534,11 +532,10 @@ class EliminationGame(ba.TeamGameActivity):
# 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()
@@ -550,18 +547,18 @@ class EliminationGame(ba.TeamGameActivity):
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)
]
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.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 3a2cea69..3531dfc5 100644
--- a/assets/src/ba_data/python/bastd/game/football.py
+++ b/assets/src/ba_data/python/bastd/game/football.py
@@ -1,27 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@@ -30,19 +12,26 @@ 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.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, Tuple, Type, Dict, Sequence, Optional,
- Union)
+ 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]):
@@ -66,51 +55,70 @@ class FootballFlag(stdflag.Flag):
self.node.connectattr('position', self.light, 'position')
+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."""
+
+ def __init__(self) -> None:
+ self.score = 0
+
+
# ba_meta export game
-class FootballTeamGame(ba.TeamGameActivity):
+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.'
+ 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
@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]):
+ def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard: Optional[Scoreboard] = Scoreboard()
@@ -120,23 +128,26 @@ class FootballTeamGame(ba.TeamGameActivity):
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',
- stdflag.get_factory().flagmaterial),
- actions=(('modify_part_collision', 'collide',
- True), ('modify_part_collision', 'physical', False),
- ('call', 'at_connect', self._handle_score)))
+ self._score_region_material = ba.Material()
+ self._score_region_material.add_actions(
+ conditions=('they_have_material', FlagFactory.get().flagmaterial),
+ 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
self._flag_respawn_timer: Optional[ba.Timer] = None
self._flag_respawn_light: Optional[ba.NodeActor] = 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]:
- touchdowns = self.settings['Score to Win'] / 7
- # NOTE: if use just touchdowns = self.settings['Score to Win'] // 7
+ touchdowns = self._score_to_win / 7
+
+ # NOTE: if use just touchdowns = self._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)
@@ -144,20 +155,16 @@ class FootballTeamGame(ba.TeamGameActivity):
return 'Score ${ARG1} touchdowns.', touchdowns
return 'Score a touchdown.'
- def get_instance_scoreboard_description(self) -> Union[str, Sequence]:
- touchdowns = self.settings['Score to Win'] / 7
+ def get_instance_description_short(self) -> Union[str, Sequence]:
+ touchdowns = self._score_to_win / 7
touchdowns = math.ceil(touchdowns)
if touchdowns > 1:
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.settings['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()
@@ -169,7 +176,7 @@ class FootballTeamGame(ba.TeamGameActivity):
'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(
@@ -178,13 +185,12 @@ class FootballTeamGame(ba.TeamGameActivity):
'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)
- def on_team_join(self, team: ba.Team) -> None:
- team.gamedata['score'] = 0
+ def on_team_join(self, team: Team) -> None:
self._update_scoreboard()
def _kill_flag(self) -> None:
@@ -198,14 +204,14 @@ class FootballTeamGame(ba.TeamGameActivity):
assert self._flag is not None
if self._flag.scored:
return
- region = ba.get_collision_info('source_node')
+ region = ba.getcollision().sourcenode
i = None
for i in range(len(self._score_regions)):
if region == self._score_regions[i].node:
break
for team in self.teams:
- if team.get_id() == i:
- team.gamedata['score'] += 7
+ if team.id == i:
+ team.score += 7
# Tell all players to celebrate.
for player in team.players:
@@ -220,8 +226,8 @@ class FootballTeamGame(ba.TeamGameActivity):
self.stats.player_scored(self._flag.last_holding_player,
50,
big_message=True)
- # end game if we won
- if team.gamedata['score'] >= self.settings['Score to Win']:
+ # End the game if we won.
+ if team.score >= self._score_to_win:
self.end_game()
ba.playsound(self._score_sound)
ba.playsound(self._cheer_sound)
@@ -232,7 +238,7 @@ class FootballTeamGame(ba.TeamGameActivity):
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)
})
@@ -242,42 +248,39 @@ class FootballTeamGame(ba.TeamGameActivity):
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.gamedata['score'])
+ results.set_team_score(team, team.score)
self.end(results=results, announce_delay=0.8)
def _update_scoreboard(self) -> None:
- win_score = self.settings['Score to Win']
assert self._scoreboard is not None
for team in self.teams:
- self._scoreboard.set_team_value(team, team.gamedata['score'],
- win_score)
+ self._scoreboard.set_team_value(team, team.score,
+ 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")
+ 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, stdflag.FlagDroppedMessage):
+ elif isinstance(msg, FlagDroppedMessage):
assert isinstance(msg.flag, FootballFlag)
msg.flag.held_count -= 1
# Respawn dead players if they're still in the game.
- elif isinstance(msg, playerspaz.PlayerSpazDeathMessage):
+ elif isinstance(msg, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
- self.respawn_player(msg.spaz.player)
+ self.respawn_player(msg.getplayer(Player))
# Respawn dead flags.
- elif isinstance(msg, stdflag.FlagDeathMessage):
+ 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(
@@ -320,22 +323,16 @@ class FootballTeamGame(ba.TeamGameActivity):
self._flag = FootballFlag(position=self._flag_spawn_pos)
-class FootballCoopGame(ba.CoopGameActivity):
- """
- Co-op variant of football
- """
+class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
+ """Co-op variant of football."""
+ name = 'Football'
tips = ['Use the pick-up button to grab the flag < ${PICKUP} >']
+ scoreconfig = ba.ScoreConfig(scoretype=ba.ScoreType.MILLISECONDS,
+ version='B')
+ default_music = ba.MusicType.FOOTBALL
- @classmethod
- def get_name(cls) -> str:
- return 'Football'
-
- @classmethod
- def get_score_info(cls) -> Dict[str, Any]:
- return {'score_type': 'milliseconds', 'score_version': 'B'}
-
- # 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'
@@ -346,17 +343,17 @@ class FootballCoopGame(ba.CoopGameActivity):
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:
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 = self.settings.get('preset', 'rookie')
+ self._preset = settings.get('preset', 'rookie')
# Load some media we need.
self._cheer_sound = ba.getsound('cheer')
@@ -368,39 +365,39 @@ class FootballCoopGame(ba.CoopGameActivity):
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),
- actions=(('modify_part_collision', 'collide',
- True), ('modify_part_collision', 'physical', False),
- ('call', 'at_connect', self._handle_score)))
+ conditions=('they_have_material', FlagFactory.get().flagmaterial),
+ 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
- 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_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[stdbomb.TNTSpawner] = None
- self._bots = spazbot.BotSet()
+ self._tntspawner: Optional[TNTSpawner] = None
+ self._bots = SpazBotSet()
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
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)
@@ -408,7 +405,7 @@ class FootballCoopGame(ba.CoopGameActivity):
# Set up the two score regions.
defs = self.map.defs
- self.score_regions.append(
+ self._score_regions.append(
ba.NodeActor(
ba.newnode('region',
attrs={
@@ -417,7 +414,7 @@ class FootballCoopGame(ba.CoopGameActivity):
'type': 'box',
'materials': [self._score_region_material]
})))
- self.score_regions.append(
+ self._score_regions.append(
ba.NodeActor(
ba.newnode('region',
attrs={
@@ -435,69 +432,60 @@ class FootballCoopGame(ba.CoopGameActivity):
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.initial_player_info is not None
- abot: Type[spazbot.SpazBot]
- bbot: Type[spazbot.SpazBot]
- cbot: Type[spazbot.SpazBot]
+ assert self.initialplayerinfos is not None
+ 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)
- self._bot_types_initial = [abot] * len(self.initial_player_info)
- bbot = (spazbot.BomberBotLite
- if self._preset == 'rookie_easy' else spazbot.BomberBot)
+ abot = (BrawlerBotLite
+ if self._preset == 'rookie_easy' else BrawlerBot)
+ 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))
- cbot = (spazbot.BomberBot
- if self._preset == 'rookie_easy' else spazbot.TriggerBot)
+ [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 = (
- [spazbot.BrawlerBot] *
- (1 if len(self.initial_player_info) < 2 else 2))
+ [BrawlerBot] * (1 if len(self.initialplayerinfos) < 2 else 2))
self._bot_types_7 = (
- [spazbot.TriggerBot] *
- (1 if len(self.initial_player_info) < 3 else 2))
+ [TriggerBot] * (1 if len(self.initialplayerinfos) < 3 else 2))
self._bot_types_14 = (
- [spazbot.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 = [spazbot.ChargerBot] * len(
- self.initial_player_info)
- abot = (spazbot.BrawlerBot
- if self._preset == 'pro' else spazbot.BrawlerBotLite)
- typed_bot_list: List[Type[spazbot.SpazBot]] = []
+ self._bot_types_initial = [ChargerBot] * len(
+ self.initialplayerinfos)
+ abot = (BrawlerBot if self._preset == 'pro' else BrawlerBotLite)
+ typed_bot_list: List[Type[SpazBot]] = []
self._bot_types_7 = (
- typed_bot_list + [abot] + [spazbot.BomberBot] *
- (1 if len(self.initial_player_info) < 3 else 2))
- bbot = (spazbot.TriggerBotPro
- if self._preset == 'pro' else spazbot.TriggerBot)
+ typed_bot_list + [abot] + [BomberBot] *
+ (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
- 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] * len(self.initial_player_info))
+ 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.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 = (
- [spazbot.ExplodeyBot] *
- (1 if len(self.initial_player_info) < 3 else 2))
+ [ExplodeyBot] * (1 if len(self.initialplayerinfos) < 3 else 2))
else:
raise Exception()
@@ -508,10 +496,13 @@ 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 = 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
+ team.score = 0
self.update_scores()
@@ -534,8 +525,8 @@ class FootballCoopGame(ba.CoopGameActivity):
}))
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,
@@ -543,9 +534,9 @@ class FootballCoopGame(ba.CoopGameActivity):
# 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._bots = SpazBotSet()
self._bot_spawn_timer = ba.Timer(1.0, self._update_bots, repeat=True)
for bottype in self._bot_types_initial:
@@ -554,15 +545,15 @@ class FootballCoopGame(ba.CoopGameActivity):
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.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,
@@ -584,13 +575,13 @@ class FootballCoopGame(ba.CoopGameActivity):
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
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.
@@ -606,12 +597,11 @@ class FootballCoopGame(ba.CoopGameActivity):
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,
@@ -622,7 +612,6 @@ class FootballCoopGame(ba.CoopGameActivity):
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):
@@ -636,9 +625,9 @@ class FootballCoopGame(ba.CoopGameActivity):
-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:
@@ -646,7 +635,7 @@ class FootballCoopGame(ba.CoopGameActivity):
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 """
@@ -660,16 +649,16 @@ class FootballCoopGame(ba.CoopGameActivity):
return
# See which score region it was.
- region = ba.get_collision_info('source_node')
+ region = ba.getcollision().sourcenode
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]:
assert team is not None
- if team.get_id() == i:
- team.gamedata['score'] += 7
+ if team.id == i:
+ team.score += 7
# Tell all players (or bots) to celebrate.
if i == 0:
@@ -682,11 +671,11 @@ class FootballCoopGame(ba.CoopGameActivity):
# If the good guys scored, add more enemies.
if i == 0:
- if self.teams[0].gamedata['score'] == 7:
+ if self.teams[0].score == 7:
assert self._bot_types_7 is not None
for bottype in self._bot_types_7:
self._spawn_bot(bottype)
- elif self.teams[0].gamedata['score'] == 14:
+ elif self.teams[0].score == 14:
assert self._bot_types_14 is not None
for bottype in self._bot_types_14:
self._spawn_bot(bottype)
@@ -705,7 +694,7 @@ class FootballCoopGame(ba.CoopGameActivity):
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)
})
@@ -722,7 +711,7 @@ class FootballCoopGame(ba.CoopGameActivity):
def on_continue(self) -> None:
# Subtract one touchdown from the bots and get them moving again.
assert self._bot_team is not None
- self._bot_team.gamedata['score'] -= 7
+ self._bot_team.score -= 7
self._bots.start_moving()
self.update_scores()
@@ -735,11 +724,10 @@ class FootballCoopGame(ba.CoopGameActivity):
for team in [self.teams[0], self._bot_team]:
assert team is not None
assert self._scoreboard is not None
- self._scoreboard.set_team_value(team, team.gamedata['score'],
- win_score)
- if team.gamedata['score'] >= win_score:
+ 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:
@@ -750,19 +738,19 @@ class FootballCoopGame(ba.CoopGameActivity):
if self._preset in ['rookie', 'rookie_easy']:
self._award_achievement('Rookie Football Victory',
sound=False)
- if self._bot_team.gamedata['score'] == 0:
+ if self._bot_team.score == 0:
self._award_achievement(
'Rookie Football Shutout', sound=False)
elif self._preset in ['pro', 'pro_easy']:
self._award_achievement('Pro Football Victory',
sound=False)
- if self._bot_team.gamedata['score'] == 0:
+ if self._bot_team.score == 0:
self._award_achievement('Pro Football Shutout',
sound=False)
elif self._preset in ['uber', 'uber_easy']:
self._award_achievement('Uber Football Victory',
sound=False)
- if self._bot_team.gamedata['score'] == 0:
+ if self._bot_team.score == 0:
self._award_achievement(
'Uber Football Shutout', sound=False)
if (not self._player_has_dropped_bomb
@@ -799,35 +787,29 @@ class FootballCoopGame(ba.CoopGameActivity):
'outcome': outcome,
'score': scoreval,
'score_order': 'decreasing',
- 'player_info': self.initial_player_info
+ 'playerinfos': self.initialplayerinfos
})
def handlemessage(self, msg: Any) -> Any:
""" handle high-level game messages """
- if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
- from bastd.actor import respawnicon
-
- # Respawn dead players.
- player = msg.spaz.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
-
- # 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)
-
+ if isinstance(msg, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
- elif isinstance(msg, spazbot.SpazBotDeathMessage):
+ # Respawn them shortly.
+ player = msg.getplayer(Player)
+ 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)
+
+ 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, spazbot.SpazBotPunchedMessage):
+ elif isinstance(msg, SpazBotPunchedMessage):
if self._preset in ['rookie', 'rookie_easy']:
if msg.damage >= 500:
self._award_achievement('Super Punch')
@@ -836,7 +818,7 @@ class FootballCoopGame(ba.CoopGameActivity):
self._award_achievement('Super Mega Punch')
# Respawn dead flags.
- elif isinstance(msg, stdflag.FlagDeathMessage):
+ 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(
@@ -857,7 +839,8 @@ class FootballCoopGame(ba.CoopGameActivity):
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:
@@ -868,10 +851,10 @@ class FootballCoopGame(ba.CoopGameActivity):
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.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 9aaca842..3964ad7e 100644
--- a/assets/src/ba_data/python/bastd/game/hockey.py
+++ b/assets/src/ba_data/python/bastd/game/hockey.py
@@ -1,42 +1,26 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (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
import ba
-from bastd.actor import playerspaz
+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, Tuple, Optional,
- Union)
+ from typing import Any, Sequence, Dict, Type, List, Optional, Union
-class PuckDeathMessage:
- """Inform an object that a puck has died."""
+class PuckDiedMessage:
+ """Inform something that a puck has died."""
def __init__(self, puck: Puck):
self.puck = puck
@@ -47,15 +31,16 @@ 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.
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)
- pmats = [ba.sharedobj('object_material'), activity.puck_material]
+ pmats = [shared.object_material, activity.puck_material]
self.node = ba.newnode('prop',
delegate=self,
attrs={
@@ -77,7 +62,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):
@@ -95,28 +80,65 @@ 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:
+ s_player = msg.get_source_player(Player)
+ if s_player is not None:
activity = self._activity()
if activity:
- if msg.source_player in activity.players:
- self.last_players_to_touch[
- msg.source_player.team.get_id(
- )] = msg.source_player
+ if s_player in activity.players:
+ self.last_players_to_touch[s_player.team.id] = s_player
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."""
+
+ def __init__(self) -> None:
+ self.score = 0
+
+
# ba_meta export game
-class HockeyGame(ba.TeamGameActivity):
+class HockeyGame(ba.TeamGameActivity[Player, 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.'
+ 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
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -126,30 +148,9 @@ class HockeyGame(ba.TeamGameActivity):
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
+ def __init__(self, settings: dict):
super().__init__(settings)
+ shared = SharedObjects.get()
self._scoreboard = Scoreboard()
self._cheer_sound = ba.getsound('cheer')
self._chant_sound = ba.getsound('crowdChant')
@@ -162,29 +163,33 @@ class HockeyGame(ba.TeamGameActivity):
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), ))
# 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()
@@ -196,30 +201,28 @@ class HockeyGame(ba.TeamGameActivity):
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['Score to Win'] == 1:
+ if self._score_to_win == 1:
return 'Score a goal.'
- return 'Score ${ARG1} goals.', self.settings['Score to Win']
+ return 'Score ${ARG1} goals.', self._score_to_win
- def get_instance_scoreboard_description(self) -> Union[str, Sequence]:
- if self.settings['Score to Win'] == 1:
+ def get_instance_description_short(self) -> Union[str, Sequence]:
+ if self._score_to_win == 1:
return 'score a goal'
- return 'score ${ARG1} goals', self.settings['Score to Win']
-
- def on_transition_in(self) -> None:
- self.default_music = ba.MusicType.HOCKEY
- super().on_transition_in()
+ return 'score ${ARG1} goals', self._score_to_win
def on_begin(self) -> None:
super().on_begin()
- self.setup_standard_time_limit(self.settings['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(
@@ -243,20 +246,20 @@ class HockeyGame(ba.TeamGameActivity):
self._update_scoreboard()
ba.playsound(self._chant_sound)
- def on_team_join(self, team: ba.Team) -> None:
- team.gamedata['score'] = 0
+ def on_team_join(self, team: Team) -> None:
self._update_scoreboard()
def _handle_puck_player_collide(self) -> None:
+ collision = ba.getcollision()
try:
- pucknode, playernode = ba.get_collision_info(
- 'source_node', 'opposing_node')
- puck = pucknode.getdelegate()
- player = playernode.getdelegate().getplayer()
- except Exception:
- player = puck = None
- if player and puck:
- puck.last_players_to_touch[player.team.get_id()] = player
+ 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
@@ -272,16 +275,16 @@ class HockeyGame(ba.TeamGameActivity):
if self._puck.scored:
return
- region = ba.get_collision_info('source_node')
+ region = ba.getcollision().sourcenode
index = 0
for index in range(len(self._score_regions)):
if region == self._score_regions[index].node:
break
for team in self.teams:
- if team.get_id() == index:
+ if team.id == index:
scoring_team = team
- team.gamedata['score'] += 1
+ team.score += 1
# Tell all players to celebrate.
for player in team.players:
@@ -290,16 +293,15 @@ 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['Score to Win']:
+ if team.score >= self._score_to_win:
self.end_game()
ba.playsound(self._foghorn_sound)
@@ -312,7 +314,7 @@ class HockeyGame(ba.TeamGameActivity):
light = ba.newnode('light',
attrs={
- 'position': ba.get_collision_info('position'),
+ 'position': ba.getcollision().position,
'height_attenuated': False,
'color': (1, 0, 0)
})
@@ -323,28 +325,26 @@ class HockeyGame(ba.TeamGameActivity):
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.gamedata['score'])
+ results.set_team_score(team, team.score)
self.end(results=results)
def _update_scoreboard(self) -> None:
- """ update scoreboard and check for winners """
- winscore = self.settings['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:
# 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.spaz.player)
+ 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/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py
index c7dc0085..7810b2e6 100644
--- a/assets/src/ba_data/python/bastd/game/keepaway.py
+++ b/assets/src/ba_data/python/bastd/game/keepaway.py
@@ -1,61 +1,84 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
+from enum import Enum
from typing import TYPE_CHECKING
import ba
-from bastd.actor import flag as stdflag
-from bastd.actor import playerspaz
+from bastd.actor.playerspaz import PlayerSpaz
+from bastd.actor.scoreboard import Scoreboard
+from bastd.actor.flag import (Flag, FlagDroppedMessage, FlagDiedMessage,
+ FlagPickedUpMessage)
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
+
+
+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, timeremaining: int) -> None:
+ self.timeremaining = timeremaining
+ self.holdingflag = False
# ba_meta export game
-class KeepAwayGame(ba.TeamGameActivity):
+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) -> Dict[str, Any]:
- return {'score_name': 'Time Held'}
+ name = 'Keep Away'
+ description = 'Carry the flag for a set length of time.'
+ 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,
+ ),
+ ]
+ scoreconfig = ba.ScoreConfig(label='Time Held')
+ default_music = ba.MusicType.KEEP_AWAY
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -66,31 +89,7 @@ class KeepAwayGame(ba.TeamGameActivity):
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
+ def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
self._swipsound = ba.getsound('swip')
@@ -109,37 +108,35 @@ class KeepAwayGame(ba.TeamGameActivity):
}
self._flag_spawn_pos: Optional[Sequence[float]] = None
self._update_timer: Optional[ba.Timer] = None
- self._holding_players: List[ba.Player] = []
- self._flag_state: Optional[int] = None
+ self._holding_players: List[Player] = []
+ self._flag_state: Optional[FlagState] = 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
+ 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['Hold Time'])
+ return 'Carry the flag for ${ARG1} seconds.', self._hold_time
- def get_instance_scoreboard_description(self) -> Union[str, Sequence]:
- return ('carry the flag for ${ARG1} seconds',
- self.settings['Hold Time'])
+ def get_instance_description_short(self) -> Union[str, Sequence]:
+ 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: ba.Team) -> None:
- team.gamedata['time_remaining'] = self.settings['Hold Time']
+ def on_team_join(self, team: Team) -> None:
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._time_limit)
self.setup_standard_powerup_drops()
self._flag_spawn_pos = self.map.get_flag_position(None)
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()
@@ -153,91 +150,82 @@ class KeepAwayGame(ba.TeamGameActivity):
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()
+ results = ba.GameResults()
for team in self.teams:
- results.set_team_score(
- team,
- self.settings['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.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 = (
+ holdingflag = (
player.actor.node.hold_node.getnodetype() == 'flag')
except Exception:
- ba.print_exception('exception checking hold flag')
- if holding_flag:
+ ba.print_exception('Error checking hold 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:
- self._flag_state = self.FLAG_CONTESTED
+ 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]
- self._flag_state = self.FLAG_HELD
- self._scoring_team = holding_team
- self._flag_light.color = ba.normalized_color(holding_team.color)
- self._flag.node.color = holding_team.color
+ elif len(holdingteams) == 1:
+ holdingteam = list(holdingteams)[0]
+ self._flag_state = FlagState.HELD
+ self._scoring_team = holdingteam
+ self._flag_light.color = ba.normalized_color(holdingteam.color)
+ self._flag.node.color = holdingteam.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)
- if self._flag_state != prev_state:
+ if self._flag_state != prevstate:
ba.playsound(self._swipsound)
def _spawn_flag(self) -> None:
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_state = self.FLAG_NEW
+ self._flag = Flag(dropped_timeout=20, position=self._flag_spawn_pos)
+ self._flag_state = FlagState.NEW
self._flag_light = ba.newnode('light',
owner=self._flag.node,
attrs={
@@ -263,20 +251,18 @@ class KeepAwayGame(ba.TeamGameActivity):
def _update_scoreboard(self) -> None:
for team in self.teams:
self._scoreboard.set_team_value(team,
- team.gamedata['time_remaining'],
- self.settings['Hold Time'],
+ team.timeremaining,
+ self._hold_time,
countdown=True)
def handlemessage(self, msg: Any) -> Any:
- if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
+ if isinstance(msg, ba.PlayerDiedMessage):
# Augment standard behavior.
super().handlemessage(msg)
- self.respawn_player(msg.spaz.player)
- elif isinstance(msg, stdflag.FlagDeathMessage):
+ self.respawn_player(msg.getplayer(Player))
+ elif isinstance(msg, FlagDiedMessage):
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 63331254..66726261 100644
--- a/assets/src/ba_data/python/bastd/game/kingofthehill.py
+++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py
@@ -1,63 +1,87 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
import weakref
+from enum import Enum
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
+from bastd.actor.scoreboard import Scoreboard
+from bastd.gameutils import SharedObjects
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
+
+
+class Player(ba.Player['Team']):
+ """Our player type for this game."""
+
+ def __init__(self) -> None:
+ self.time_at_flag = 0
+
+
+class Team(ba.Team[Player]):
+ """Our team type for this game."""
+
+ def __init__(self, time_remaining: int) -> None:
+ self.time_remaining = time_remaining
# ba_meta export game
-class KingOfTheHillGame(ba.TeamGameActivity):
+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) -> Dict[str, Any]:
- return {'score_name': 'Time Held'}
+ name = 'King of the Hill'
+ description = 'Secure the flag for a set length of time.'
+ 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,
+ ),
+ ]
+ scoreconfig = ba.ScoreConfig(label='Time Held')
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -67,31 +91,9 @@ class KingOfTheHillGame(ba.TeamGameActivity):
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
+ def __init__(self, settings: dict):
super().__init__(settings)
+ shared = SharedObjects.get()
self._scoreboard = Scoreboard()
self._swipsound = ba.getsound('swip')
self._tick_sound = ba.getsound('tick')
@@ -108,54 +110,48 @@ class KingOfTheHillGame(ba.TeamGameActivity):
1: ba.getsound('announceOne')
}
self._flag_pos: Optional[Sequence[float]] = None
- self._flag_state: Optional[int] = None
- self._flag: Optional[stdflag.Flag] = None
+ self._flag_state: Optional[FlagState] = 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(
- 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))))
+ conditions=('they_have_material', shared.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)),
+ ))
+
+ # 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['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['Hold Time'])
+ def get_instance_description_short(self) -> Union[str, Sequence]:
+ 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['Hold Time']
- self._update_scoreboard()
-
- def on_player_join(self, player: ba.Player) -> None:
- ba.TeamGameActivity.on_player_join(self, 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['Time Limit'])
+ 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)
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_state = FlagState.NEW
+ Flag.project_stand(self._flag_pos)
+ self._flag = Flag(position=self._flag_pos,
+ touchable=False,
+ color=(1, 1, 1))
self._flag_light = ba.newnode('light',
attrs={
'position': self._flag_pos,
@@ -164,12 +160,8 @@ class KingOfTheHillGame(ba.TeamGameActivity):
'radius': 0.4,
'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,
@@ -184,68 +176,62 @@ class KingOfTheHillGame(ba.TeamGameActivity):
# 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']])
- except Exception:
- pass
+ numsound = self._countdownsounds.get(scoring_team.time_remaining)
+ if numsound is not None:
+ ba.playsound(numsound)
# 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()
+ results = ba.GameResults()
for team in self.teams:
- results.set_team_score(
- team,
- self.settings['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
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)
@@ -253,35 +239,35 @@ class KingOfTheHillGame(ba.TeamGameActivity):
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:
+ 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
# 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['Hold Time'],
+ team.time_remaining,
+ self._hold_time,
countdown=True)
def handlemessage(self, msg: Any) -> Any:
- if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
+ if isinstance(msg, ba.PlayerDiedMessage):
super().handlemessage(msg) # Augment default.
- # No longer can count as at_flag once dead.
- player = msg.spaz.player
- player.gamedata['at_flag'] = 0
+ # No longer can count as time_at_flag once dead.
+ 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 94f8609f..9be79902 100644
--- a/assets/src/ba_data/python/bastd/game/meteorshower.py
+++ b/assets/src/ba_data/python/bastd/game/meteorshower.py
@@ -1,27 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@@ -29,45 +11,44 @@ import random
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.onscreentimer import OnScreenTimer
if TYPE_CHECKING:
- from typing import Any, Tuple, Sequence, Optional, List, Dict, Type
- from bastd.actor.onscreentimer import OnScreenTimer
+ from typing import Any, Sequence, Optional, List, Dict, Type, Type
+
+
+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
- def get_name(cls) -> str:
- return 'Meteor Shower'
+ name = 'Meteor Shower'
+ description = 'Dodge the falling bombs.'
+ available_settings = [ba.BoolSetting('Epic Mode', default=False)]
+ scoreconfig = ba.ScoreConfig(label='Survived',
+ scoretype=ba.ScoreType.MILLISECONDS,
+ version='B')
- @classmethod
- def get_score_info(cls) -> Dict[str, Any]:
- return {
- 'score_name': 'Survived',
- 'score_type': 'milliseconds',
- 'score_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:
@@ -75,43 +56,34 @@ class MeteorShowerGame(ba.TeamGameActivity):
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)
- if self.settings['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:
- self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
- else ba.MusicType.SURVIVAL)
- super().on_transition_in()
+ # Some base class overrides:
+ self.default_music = (ba.MusicType.EPIC
+ if self._epic_mode else ba.MusicType.SURVIVAL)
+ if self._epic_mode:
+ self.slow_motion = True
- # Called when our game actually starts.
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
# 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._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._epic_mode:
delay *= 0.25
ba.timer(delay, self._set_meteor_timer)
@@ -121,30 +93,31 @@ 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.getname(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
- player.gamedata['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.
- ba.TeamGameActivity.on_player_leave(self, player)
+ super().on_player_leave(player)
# A departing player may trigger game-over.
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
@@ -159,15 +132,16 @@ 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, ba.PlayerDiedMessage):
# 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
+ # assert isinstance(msg.spaz.player
+ msg.getplayer(Player).death_time = curtime
# In co-op mode, end the game the instant everyone dies
# (more accurate looking).
@@ -179,13 +153,14 @@ 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)
else:
# Default handler:
- super().handlemessage(msg)
+ return super().handlemessage(msg)
+ return None
def _check_end_game(self) -> None:
living_team_count = 0
@@ -234,36 +209,35 @@ 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:
+ 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 player.death_time is None:
+ survived = True
+ 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(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(player.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
@@ -272,7 +246,7 @@ class MeteorShowerGame(ba.TeamGameActivity):
# 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
@@ -281,10 +255,13 @@ 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:
+ assert player.death_time is not None
longest_life = max(longest_life,
- player.gamedata['death_time'] - start_time)
- results.set_team_score(team, longest_life)
+ player.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/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py
index 5f19131a..37ba0215 100644
--- a/assets/src/ba_data/python/bastd/game/ninjafight.py
+++ b/assets/src/ba_data/python/bastd/game/ninjafight.py
@@ -1,27 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@@ -29,36 +11,34 @@ 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.spazbot import SpazBotSet, ChargerBot, SpazBotDiedMessage
+from bastd.actor.onscreentimer import OnScreenTimer
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):
+class NinjaFightGame(ba.TeamGameActivity[Player, Team]):
"""
A co-op game where you try to defeat a group
of Ninjas as fast as possible
"""
- @classmethod
- def get_name(cls) -> str:
- return 'Ninja Fight'
-
- @classmethod
- def get_score_info(cls) -> Dict[str, Any]:
- return {
- 'score_type': 'milliseconds',
- 'lower_is_better': True,
- 'score_name': 'Time'
- }
-
- @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?'
+ 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]:
@@ -74,59 +54,54 @@ class NinjaFightGame(ba.TeamGameActivity):
# 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
- self._timer: Optional[onscreentimer.OnScreenTimer] = None
- self._bots = spazbot.BotSet()
-
- # 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()
+ self._timer: Optional[OnScreenTimer] = None
+ self._bots = SpazBotSet()
+ self._preset = str(settings['preset'])
# Called when our game actually begins.
def on_begin(self) -> None:
super().on_begin()
- is_pro = self.settings.get('preset') == 'pro'
+ is_pro = self._preset == 'pro'
# In pro mode there's no powerups.
if not is_pro:
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.
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:
+ assert self.initialplayerinfos is not None
+ if len(self.initialplayerinfos) > 2 or is_pro:
ba.timer(
5.0, lambda: self._bots.spawn_bot(
- spazbot.ChargerBot, pos=(0, 3, -5), spawn_time=3.0))
- if len(self.initial_player_info) > 3 or is_pro:
+ ChargerBot, pos=(0, 3, -5), spawn_time=3.0))
+ if len(self.initialplayerinfos) > 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: ba.Player) -> ba.Actor:
+ def spawn_player(self, player: Player) -> ba.Actor:
# Let's spawn close to the center.
spawn_center = (0, 3, -2)
@@ -148,20 +123,22 @@ class NinjaFightGame(ba.TeamGameActivity):
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.spaz.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):
+ 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
# 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
@@ -172,19 +149,14 @@ class NinjaFightGame(ba.TeamGameActivity):
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
+ # 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/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py
index 50648987..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..
@@ -27,21 +9,121 @@ 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 import bomb as stdbomb
-from bastd.actor import playerspaz, spazbot
+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 (
+ SpazBotDiedMessage, SpazBotSet, 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 OnslaughtGame(ba.CoopGameActivity):
+@dataclass
+class Wave:
+ """A wave of enemies."""
+ entries: List[Union[Spawn, Spacing, Delay, None]]
+ base_angle: float = 0.0
+
+
+@dataclass
+class Spawn:
+ """A bot spawn event 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 between events 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 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']):
+ """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."""
+
+
+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]]] = [
+ name = 'Onslaught'
+ description = 'Defeat all enemies.'
+
+ 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.',
@@ -52,34 +134,22 @@ class OnslaughtGame(ba.CoopGameActivity):
'Your punches do much more damage if you are running or spinning.'
]
- @classmethod
- def get_name(cls) -> str:
- return 'Onslaught'
+ # Show messages when players die since it matters here.
+ announce_player_deaths = True
- @classmethod
- def get_description(cls, sessiontype: Type[ba.Session]) -> str:
- return 'Defeat all enemies.'
+ def __init__(self, settings: dict):
- 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'
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')
@@ -101,7 +171,7 @@ class OnslaughtGame(ba.CoopGameActivity):
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
@@ -109,10 +179,10 @@ class OnslaughtGame(ba.CoopGameActivity):
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._tntspawner: Optional[stdbomb.TNTSpawner] = None
- self._bots: Optional[spazbot.BotSet] = None
+ self._excluded_powerups: Optional[List[str]] = None
+ self._waves: List[Wave] = []
+ self._tntspawner: Optional[TNTSpawner] = 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
@@ -124,51 +194,46 @@ class OnslaughtGame(ba.CoopGameActivity):
self._tnt_kills = 0
def on_transition_in(self) -> None:
- from bastd.actor.scoreboard import Scoreboard
super().on_transition_in()
+ customdata = ba.getsession().customdata
# 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 hasattr(ba.getsession(),
- '_g_showed_onslaught_land_mine_tip'):
- # pylint: disable=protected-access
- ba.getsession( # type: ignore
- )._g_showed_onslaught_land_mine_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 ['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 hasattr(ba.getsession(), '_g_showed_onslaught_tnt_tip'):
- # pylint: disable=protected-access
- ba.getsession( # type: ignore
- )._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 ['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 hasattr(ba.getsession(), '_g_showed_onslaught_curse_tip'):
- # pylint: disable=protected-access
- ba.getsession( # type: ignore
- )._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',
@@ -186,346 +251,312 @@ class OnslaughtGame(ba.CoopGameActivity):
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': spazbot.BomberBotLite, 'spacing': 5},
- ] * player_count},
- {'base_angle': 130,
- 'entries': [
- {'type': spazbot.BrawlerBotLite, 'spacing': 5},
- ] * player_count},
- {'base_angle': 195,
- 'entries': [
- {'type': spazbot.BomberBotLite, 'spacing': 10},
- ] * (player_count + 1)},
- {'base_angle': 130,
- 'entries': [
- {'type': spazbot.BrawlerBotLite, 'spacing': 10},
- ] * (player_count + 1)},
- {'base_angle': 130,
- 'entries': [
- {'type': spazbot.BrawlerBotLite, 'spacing': 5}
+ Wave(base_angle=195,
+ entries=[
+ Spawn(BomberBotLite, spacing=5),
+ ] * player_count),
+ Wave(base_angle=130,
+ entries=[
+ Spawn(BrawlerBotLite, spacing=5),
+ ] * player_count),
+ Wave(base_angle=195,
+ entries=[Spawn(BomberBotLite, spacing=10)] *
+ (player_count + 1)),
+ Wave(base_angle=130,
+ entries=[
+ Spawn(BrawlerBotLite, spacing=10),
+ ] * (player_count + 1)),
+ Wave(base_angle=130,
+ entries=[
+ Spawn(BrawlerBotLite, spacing=5)
if player_count > 1 else None,
- {'type': spazbot.BrawlerBotLite, 'spacing': 5},
- {'type': None, 'spacing': 30},
- {'type': spazbot.BomberBotLite, 'spacing': 5}
+ Spawn(BrawlerBotLite, spacing=5),
+ Spacing(30),
+ Spawn(BomberBotLite, spacing=5)
if player_count > 3 else None,
- {'type': spazbot.BomberBotLite, 'spacing': 5},
- {'type': None, 'spacing': 30},
- {'type': spazbot.BrawlerBotLite, 'spacing': 5},
- {'type': spazbot.BrawlerBotLite, 'spacing': 5}
+ Spawn(BomberBotLite, spacing=5),
+ Spacing(30),
+ Spawn(BrawlerBotLite, spacing=5),
+ Spawn(BrawlerBotLite, spacing=5)
if player_count > 2 else None,
- ]},
- {'base_angle': 195,
- 'entries': [
- {'type': spazbot.TriggerBot, 'spacing': 90},
- {'type': spazbot.TriggerBot, 'spacing': 90}
+ ]),
+ Wave(base_angle=195,
+ entries=[
+ Spawn(TriggerBot, spacing=90),
+ Spawn(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': spazbot.ChargerBot, 'point': 'left_upper_more'}
- if player_count > 2 else None,
- {'type': spazbot.ChargerBot, 'point': 'left_upper'},
- ]},
- {'entries': [
- {'type': spazbot.BomberBotStaticLite,
- 'point': 'turret_top_right'},
- {'type': spazbot.BrawlerBotLite, 'point': 'right_upper'},
- {'type': spazbot.BrawlerBotLite, 'point': 'right_lower'}
- if player_count > 1 else None,
- {'type': spazbot.BomberBotStaticLite,
- 'point': 'turret_bottom_right'}
- if player_count > 2 else None,
- ]},
- {'entries': [
- {'type': spazbot.BomberBotStaticLite,
- 'point': 'turret_bottom_left'},
- {'type': spazbot.TriggerBot, 'point': 'left'},
- {'type': spazbot.TriggerBot, 'point': 'left_lower'}
- if player_count > 1 else None,
- {'type': spazbot.TriggerBot, 'point': 'left_upper'}
- if player_count > 2 else None,
- ]},
- {'entries': [
- {'type': spazbot.BrawlerBotLite, 'point': 'top_right'},
- {'type': spazbot.BrawlerBot, 'point': 'top_half_right'}
- if player_count > 1 else None,
- {'type': spazbot.BrawlerBotLite, 'point': 'top_left'},
- {'type': spazbot.BrawlerBotLite, 'point': 'top_half_left'}
- if player_count > 2 else None,
- {'type': spazbot.BrawlerBot, 'point': 'top'},
- {'type': spazbot.BomberBotStaticLite,
- 'point': 'turret_top_middle'},
- ]},
- {'entries': [
- {'type': spazbot.TriggerBotStatic,
- 'point': 'turret_bottom_left'},
- {'type': spazbot.TriggerBotStatic,
- 'point': 'turret_bottom_right'},
- {'type': spazbot.TriggerBot, 'point': 'bottom'},
- {'type': spazbot.TriggerBot, 'point': 'bottom_half_right'}
- if player_count > 1 else None,
- {'type': spazbot.TriggerBot, 'point': 'bottom_half_left'}
- if player_count > 2 else None,
- ]},
- {'entries': [
- {'type': spazbot.BomberBotStaticLite,
- 'point': 'turret_top_left'},
- {'type': spazbot.BomberBotStaticLite,
- 'point': 'turret_top_right'},
- {'type': spazbot.ChargerBot, 'point': 'bottom'},
- {'type': spazbot.ChargerBot, 'point': 'bottom_half_left'}
- if player_count > 1 else None,
- {'type': spazbot.ChargerBot, 'point': 'bottom_half_right'}
- if player_count > 2 else None,
- ]},
- ] # yapf: disable
+ Wave(entries=[
+ Spawn(ChargerBot, Point.LEFT_UPPER_MORE
+ ) if player_count > 2 else None,
+ Spawn(ChargerBot, Point.LEFT_UPPER),
+ ]),
+ Wave(entries=[
+ 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=[
+ 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=[
+ 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=[
+ 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=[
+ 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,
+ ]),
+ ]
- 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': spazbot.BrawlerBot, 'spacing': 12}
+ Wave(base_angle=-50,
+ entries=[
+ Spawn(BrawlerBot, spacing=12)
if player_count > 3 else None,
- {'type': spazbot.BrawlerBot, 'spacing': 12},
- {'type': spazbot.BomberBot, 'spacing': 6},
- {'type': spazbot.BomberBot, 'spacing': 6}
- if self._preset == 'pro' else None,
- {'type': spazbot.BomberBot, 'spacing': 6}
+ Spawn(BrawlerBot, spacing=12),
+ Spawn(BomberBot, spacing=6),
+ Spawn(BomberBot, spacing=6)
+ if self._preset is Preset.PRO else None,
+ Spawn(BomberBot, spacing=6)
if player_count > 1 else None,
- {'type': spazbot.BrawlerBot, 'spacing': 12},
- {'type': spazbot.BrawlerBot, 'spacing': 12}
+ Spawn(BrawlerBot, spacing=12),
+ Spawn(BrawlerBot, spacing=12)
if player_count > 2 else None,
- ]},
- {'base_angle': 180,
- 'entries': [
- {'type': spazbot.BrawlerBot, 'spacing': 6}
+ ]),
+ Wave(base_angle=180,
+ entries=[
+ Spawn(BrawlerBot, spacing=6)
if player_count > 3 else None,
- {'type': spazbot.BrawlerBot, 'spacing': 6}
- if self._preset == 'pro' else None,
- {'type': spazbot.BrawlerBot, 'spacing': 6},
- {'type': spazbot.ChargerBot, 'spacing': 45},
- {'type': spazbot.ChargerBot, 'spacing': 45}
+ Spawn(BrawlerBot, spacing=6)
+ if self._preset is Preset.PRO else None,
+ Spawn(BrawlerBot, spacing=6),
+ Spawn(ChargerBot, spacing=45),
+ Spawn(ChargerBot, spacing=45)
if player_count > 1 else None,
- {'type': spazbot.BrawlerBot, 'spacing': 6},
- {'type': spazbot.BrawlerBot, 'spacing': 6}
- if self._preset == 'pro' else None,
- {'type': spazbot.BrawlerBot, 'spacing': 6}
+ Spawn(BrawlerBot, spacing=6),
+ Spawn(BrawlerBot, spacing=6)
+ if self._preset is Preset.PRO else None,
+ Spawn(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}
- if self._preset == 'pro' else None,
- {'type': spazbot.TriggerBot, 'spacing': 30}
+ ]),
+ Wave(base_angle=0,
+ entries=[
+ Spawn(ChargerBot, spacing=30),
+ Spawn(TriggerBot, spacing=30),
+ Spawn(TriggerBot, spacing=30),
+ Spawn(TriggerBot, spacing=30)
+ if self._preset is Preset.PRO else None,
+ Spawn(TriggerBot, spacing=30)
if player_count > 1 else None,
- {'type': spazbot.TriggerBot, 'spacing': 30}
+ Spawn(TriggerBot, spacing=30)
if player_count > 3 else None,
- {'type': spazbot.ChargerBot, 'spacing': 30},
- ]},
- {'base_angle': 90,
- 'entries': [
- {'type': spazbot.StickyBot, 'spacing': 50},
- {'type': spazbot.StickyBot, 'spacing': 50}
- if self._preset == 'pro' else None,
- {'type': spazbot.StickyBot, 'spacing': 50},
- {'type': spazbot.StickyBot, 'spacing': 50}
- if player_count > 1 else None,
- {'type': spazbot.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}
- if self._preset == 'pro' else None,
- {'type': spazbot.TriggerBot, 'spacing': 72},
- {'type': spazbot.TriggerBot, 'spacing': 72},
- {'type': spazbot.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}
- if self._preset == 'pro' else None,
- {'type': spazbot.ChargerBotProShielded, 'spacing': 50}
+ Spawn(ChargerBot, spacing=30),
+ ]),
+ Wave(base_angle=90,
+ entries=[
+ Spawn(StickyBot, spacing=50),
+ Spawn(StickyBot, spacing=50)
+ if self._preset is Preset.PRO else None,
+ Spawn(StickyBot, spacing=50),
+ Spawn(StickyBot, spacing=50)
if player_count > 1 else None,
- {'type': spazbot.ChargerBotProShielded, 'spacing': 50}
+ Spawn(StickyBot, spacing=50)
+ if player_count > 3 else None,
+ ]),
+ Wave(base_angle=0,
+ entries=[
+ Spawn(TriggerBot, spacing=72),
+ Spawn(TriggerBot, spacing=72),
+ Spawn(TriggerBot, spacing=72)
+ if self._preset is Preset.PRO else None,
+ Spawn(TriggerBot, spacing=72),
+ Spawn(TriggerBot, spacing=72),
+ Spawn(TriggerBot, spacing=36)
if player_count > 2 else None,
- ]}
- ] # yapf: disable
+ ]),
+ Wave(base_angle=30,
+ entries=[
+ Spawn(ChargerBotProShielded, spacing=50),
+ Spawn(ChargerBotProShielded, spacing=50),
+ Spawn(ChargerBotProShielded, spacing=50)
+ if self._preset is Preset.PRO else None,
+ Spawn(ChargerBotProShielded, spacing=50)
+ if player_count > 1 else None,
+ Spawn(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:
+ # 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()
self._have_tnt = True
- self._excludepowerups = []
+ self._excluded_powerups = []
self._waves = [
- {'entries': [
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_middle_left'}
- if hard else None,
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_middle_right'},
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_left'}
- if player_count > 2 else None,
- {'type': spazbot.ExplodeyBot, 'point': 'top_right'},
- {'type': 'delay', 'duration': 4.0},
- {'type': spazbot.ExplodeyBot, 'point': 'top_left'},
- ]},
- {'entries': [
- {'type': spazbot.ChargerBot, 'point': 'left'},
- {'type': spazbot.ChargerBot, 'point': 'right'},
- {'type': spazbot.ChargerBot, 'point': 'right_upper_more'}
- if player_count > 2 else None,
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_left'},
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_right'},
- ]},
- {'entries': [
- {'type': spazbot.TriggerBotPro, 'point': 'top_right'},
- {'type': spazbot.TriggerBotPro,
- 'point': 'right_upper_more'}
- if player_count > 1 else None,
- {'type': spazbot.TriggerBotPro, 'point': 'right_upper'},
- {'type': spazbot.TriggerBotPro, 'point': 'right_lower'}
- if hard else None,
- {'type': spazbot.TriggerBotPro,
- 'point': 'right_lower_more'}
- if player_count > 2 else None,
- {'type': spazbot.TriggerBotPro, 'point': 'bottom_right'},
- ]},
- {'entries': [
- {'type': spazbot.ChargerBotProShielded,
- 'point': 'bottom_right'},
- {'type': spazbot.ChargerBotProShielded, 'point': 'bottom'}
- if player_count > 2 else None,
- {'type': spazbot.ChargerBotProShielded,
- 'point': 'bottom_left'},
- {'type': spazbot.ChargerBotProShielded, 'point': 'top'}
- if hard else None,
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_middle'},
- ]},
- {'entries': [
- {'type': spazbot.ExplodeyBot, 'point': 'left_upper'},
- {'type': 'delay', 'duration': 1.0},
- {'type': spazbot.BrawlerBotProShielded,
- 'point': 'left_lower'},
- {'type': spazbot.BrawlerBotProShielded,
- 'point': 'left_lower_more'},
- {'type': 'delay', 'duration': 4.0},
- {'type': spazbot.ExplodeyBot, 'point': 'right_upper'},
- {'type': 'delay', 'duration': 1.0},
- {'type': spazbot.BrawlerBotProShielded,
- 'point': 'right_lower'},
- {'type': spazbot.BrawlerBotProShielded,
- 'point': 'right_upper_more'},
- {'type': 'delay', 'duration': 4.0},
- {'type': spazbot.ExplodeyBot, 'point': 'left'},
- {'type': 'delay', 'duration': 5.0},
- {'type': spazbot.ExplodeyBot, 'point': 'right'},
- ]},
- {'entries': [
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_left'},
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_right'},
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_bottom_left'},
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_bottom_right'},
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_middle_left'} if hard else None,
- {'type': spazbot.BomberBotProStatic,
- 'point': 'turret_top_middle_right'} if hard else None,
- ]
- }] # yapf: disable
+ Wave(entries=[
+ 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),
+ Spawn(ExplodeyBot, Point.TOP_LEFT),
+ ]),
+ Wave(entries=[
+ 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=[
+ 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=[
+ 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=[
+ Spawn(ExplodeyBot, Point.LEFT_UPPER),
+ Delay(1.0),
+ Spawn(BrawlerBotProShielded, Point.LEFT_LOWER),
+ Spawn(BrawlerBotProShielded, Point.LEFT_LOWER_MORE),
+ Delay(4.0),
+ Spawn(ExplodeyBot, Point.RIGHT_UPPER),
+ Delay(1.0),
+ Spawn(BrawlerBotProShielded, Point.RIGHT_LOWER),
+ Spawn(BrawlerBotProShielded, Point.RIGHT_UPPER_MORE),
+ Delay(4.0),
+ Spawn(ExplodeyBot, Point.LEFT),
+ Delay(5.0),
+ Spawn(ExplodeyBot, Point.RIGHT),
+ ]),
+ Wave(entries=[
+ 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,
+ ])
+ ]
# 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:
- raise Exception('Invalid preset: ' + str(self._preset))
+ raise RuntimeError(f'Invalid preset: {self._preset}')
# 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).
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 = 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([])
@@ -537,83 +568,29 @@ class OnslaughtGame(ba.CoopGameActivity):
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:
@@ -622,17 +599,88 @@ class OnslaughtGame(ba.CoopGameActivity):
return groups
- def spawn_player(self, player: ba.Player) -> ba.Actor:
+ 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.
- 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
@@ -643,11 +691,10 @@ class OnslaughtGame(ba.CoopGameActivity):
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,
@@ -658,7 +705,6 @@ class OnslaughtGame(ba.CoopGameActivity):
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)):
@@ -674,17 +720,17 @@ class OnslaughtGame(ba.CoopGameActivity):
-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."""
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:
@@ -695,13 +741,27 @@ class OnslaughtGame(ba.CoopGameActivity):
'outcome': outcome,
'score': score,
'fail_message': fail_message,
- 'player_info': self.initial_player_info
+ 'playerinfos': self.initialplayerinfos
},
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
@@ -710,15 +770,14 @@ class OnslaughtGame(ba.CoopGameActivity):
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))
+ won = (self._wavenum == 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,
@@ -726,16 +785,15 @@ class OnslaughtGame(ba.CoopGameActivity):
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.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
@@ -744,28 +802,7 @@ class OnslaughtGame(ba.CoopGameActivity):
scale=1.0,
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
ba.playsound(self._winsound)
@@ -779,10 +816,10 @@ class OnslaughtGame(ba.CoopGameActivity):
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))
@@ -791,10 +828,10 @@ class OnslaughtGame(ba.CoopGameActivity):
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'),
@@ -803,20 +840,17 @@ class OnslaughtGame(ba.CoopGameActivity):
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()
- 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():
@@ -846,14 +880,13 @@ class OnslaughtGame(ba.CoopGameActivity):
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.gamedata['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.gamedata['respawn_wave']))
+ subs=[('${PLAYER}', player.getname()),
+ ('${WAVE}', str(player.respawn_wave))
])
text = ba.Lstr(value='${A}${B}\n',
subs=[
@@ -862,173 +895,52 @@ class OnslaughtGame(ba.CoopGameActivity):
])
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():
+ if self._wavenum > 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._wavenum):
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:
+ if self._wavenum == 1:
spawn_time = 3.973
tval += 0.5
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 = [
- 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
- ]
- if level > 5:
- bot_types2 += [
- spazbot.ExplodeyBot,
- spazbot.TriggerBotProShielded,
- spazbot.BrawlerBotProShielded,
- spazbot.ChargerBotProShielded,
- ]
- if level > 7:
- bot_types2 += [
- spazbot.ExplodeyBot,
- spazbot.TriggerBotProShielded,
- spazbot.BrawlerBotProShielded,
- spazbot.ChargerBotProShielded,
- ]
- if level > 10:
- bot_types2 += [
- spazbot.TriggerBotProShielded,
- spazbot.TriggerBotProShielded,
- spazbot.TriggerBotProShielded,
- spazbot.TriggerBotProShielded
- ]
- if level > 13:
- bot_types2 += [
- spazbot.TriggerBotProShielded,
- spazbot.TriggerBotProShielded,
- spazbot.TriggerBotProShielded,
- spazbot.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,
@@ -1041,9 +953,33 @@ class OnslaughtGame(ba.CoopGameActivity):
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._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))
+
+ 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._wavenum))]),
+ 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=[
@@ -1067,15 +1003,13 @@ class OnslaughtGame(ba.CoopGameActivity):
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._wavenum) +
+ ('' if self._preset
+ in [Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT] else
+ ('/' + str(len(self._waves)))))])
self._wave_text = ba.NodeActor(
ba.newnode('text',
attrs={
@@ -1091,20 +1025,119 @@ class OnslaughtGame(ba.CoopGameActivity):
'text': wttxt
}))
+ def _bot_levels_for_wave(self) -> List[List[Type[SpazBot]]]:
+ level = self._wavenum
+ 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[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))]
+ 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, Spawn(bot_type, spacing=spacing))
+ else:
+ entries.append(Spawn(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._wavenum
+ 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[Spawn, 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,
- spaz_type: Type[spazbot.SpazBot],
+ 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[point.value]
assert self._bots is not None
self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time)
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:
@@ -1134,7 +1167,7 @@ class OnslaughtGame(ba.CoopGameActivity):
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:
@@ -1146,107 +1179,49 @@ class OnslaughtGame(ba.CoopGameActivity):
def handlemessage(self, msg: Any) -> Any:
- # FIXME; tidy this up
- # 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):
+ msg.spaz.getplayer(Player, True).has_been_hurt = True
self._a_player_has_been_hurt = True
elif isinstance(msg, ba.PlayerScoredMessage):
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.spaz.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:
- if self._wave < 10:
- player.gamedata['respawn_wave'] = max(2, self._wave + 1)
- elif self._wave < 15:
- player.gamedata['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.gamedata['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, spazbot.SpazBotDeathMessage):
- pts, importance = msg.badguy.get_death_points(msg.how)
+ elif isinstance(msg, SpazBotDiedMessage):
+ pts, importance = msg.spazbot.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:
- assert msg.badguy.node
- target = msg.badguy.node.position
- except Exception:
- ba.print_exception()
+ if msg.spazbot.node:
+ target = msg.spazbot.node.position
+ 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.
@@ -1256,6 +1231,58 @@ class OnslaughtGame(ba.CoopGameActivity):
else:
super().handlemessage(msg)
+ def _handle_kill_achievements(self, msg: SpazBotDiedMessage) -> None:
+ if self._preset in {Preset.TRAINING, Preset.TRAINING_EASY}:
+ self._handle_training_kill_achievements(msg)
+ elif self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}:
+ 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.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.spazbot.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:
+ if msg.spazbot.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'))
+
+ def _handle_rookie_kill_achievements(self,
+ msg: SpazBotDiedMessage) -> None:
+ # Land-mine achievement:
+ 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')
+
+ def _handle_training_kill_achievements(self,
+ msg: SpazBotDiedMessage) -> None:
+ # Toss-off-map achievement:
+ 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')
+
def _set_can_end_wave(self) -> None:
self._can_end_wave = True
@@ -1273,14 +1300,12 @@ class OnslaughtGame(ba.CoopGameActivity):
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):
# 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 bdf0a513..0a058ac4 100644
--- a/assets/src/ba_data/python/bastd/game/race.py
+++ b/assets/src/ba_data/python/bastd/game/race.py
@@ -1,27 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@@ -31,7 +13,9 @@ 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
+from bastd.actor.scoreboard import Scoreboard
+from bastd.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict,
@@ -66,25 +50,83 @@ class RaceRegion(ba.Actor):
})
+class Player(ba.Player['Team']):
+ """Our player type for this game."""
+
+ def __init__(self) -> None:
+ self.distance_txt: Optional[ba.Node] = None
+ self.last_region = 0
+ self.lap = 0
+ self.distance = 0.0
+ self.finished = False
+ self.rank: Optional[int] = None
+
+
+class Team(ba.Team[Player]):
+ """Our team type for this game."""
+
+ def __init__(self) -> None:
+ self.time: Optional[float] = None
+ self.lap = 0
+ self.finished = False
+
+
# ba_meta export game
-class RaceGame(ba.TeamGameActivity):
+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!'
+ scoreconfig = ba.ScoreConfig(label='Time',
+ lower_is_better=True,
+ scoretype=ba.ScoreType.MILLISECONDS)
@classmethod
- def get_description(cls, sessiontype: Type[ba.Session]) -> str:
- return 'Run real fast!'
+ 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),
+ ]
- @classmethod
- def get_score_info(cls) -> Dict[str, Any]:
- return {
- 'score_name': 'Time',
- 'lower_is_better': True,
- 'score_type': 'milliseconds'
- }
+ # We have some specific settings in teams mode.
+ if issubclass(sessiontype, ba.DualTeamSession):
+ settings.append(
+ ba.BoolSetting('Entire Team Must Finish', default=False))
+ return settings
@classmethod
def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool:
@@ -94,48 +136,10 @@ class RaceGame(ba.TeamGameActivity):
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
return ba.getmaps('race')
- @classmethod
- def get_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
- })] # yapf: disable
-
- if issubclass(sessiontype, ba.DualTeamSession):
- settings.append(('Entire Team Must Finish', {'default': False}))
- return settings
-
- def __init__(self, settings: Dict[str, Any]):
- from bastd.actor.scoreboard import Scoreboard
+ def __init__(self, settings: dict):
self._race_started = False
super().__init__(settings)
self._scoreboard = Scoreboard()
- if self.settings['Epic Mode']:
- self.slow_motion = True
self._score_sound = ba.getsound('score')
self._swipsound = ba.getsound('swip')
self._last_team_time: Optional[float] = None
@@ -154,41 +158,52 @@ class RaceGame(ba.TeamGameActivity):
self._player_order_update_timer: Optional[ba.Timer] = None
self._start_lights: Optional[List[ba.Node]] = None
self._bomb_spawn_timer: Optional[ba.Timer] = None
+ self._laps = int(settings['Laps'])
+ self._entire_team_must_finish = bool(
+ settings.get('Entire Team Must Finish', False))
+ self._time_limit = float(settings['Time Limit'])
+ self._mine_spawning = int(settings['Mine Spawning'])
+ self._bomb_spawning = int(settings['Bomb Spawning'])
+ self._epic_mode = bool(settings['Epic Mode'])
+
+ # Base class overrides.
+ self.slow_motion = self._epic_mode
+ self.default_music = (ba.MusicType.EPIC_RACE
+ if self._epic_mode else ba.MusicType.RACE)
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._entire_team_must_finish):
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._laps > 1:
+ return 'Run ${ARG1} laps.' + t_str, self._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']
+ def get_instance_description_short(self) -> Union[str, Sequence]:
+ if self._laps > 1:
+ return 'run ${ARG1} laps', self._laps
return 'run 1 lap'
def on_transition_in(self) -> None:
- self.default_music = (ba.MusicType.EPIC_RACE
- if self.settings['Epic Mode'] else
- ba.MusicType.RACE)
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)))
- 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
@@ -207,19 +222,16 @@ class RaceGame(ba.TeamGameActivity):
# 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')
+ collision = ba.getcollision()
try:
- player = playernode.getdelegate().getplayer()
- except Exception:
- player = None
- region = region_node.getdelegate()
- if not player or not region:
+ region = collision.sourcenode.getdelegate(RaceRegion, True)
+ player = collision.opposingnode.getdelegate(PlayerSpaz,
+ True).getplayer(
+ Player, True)
+ except ba.NotFoundError:
return
- assert isinstance(player, ba.Player)
- assert isinstance(region, RaceRegion)
- last_region = player.gamedata['last_region']
+ last_region = player.last_region
this_region = region.index
if last_region != this_region:
@@ -234,34 +246,30 @@ class RaceGame(ba.TeamGameActivity):
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
# front-most race-point.
- if player.gamedata['rank'] == 0:
+ if player.rank == 0:
self._front_race_region = this_region
- player.gamedata['last_region'] = this_region
+ player.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'] + 1)
+ player.lap = min(self._laps, player.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'):
- team.gamedata['lap'] = min(
- [p.gamedata['lap'] for p in team.players])
+ if isinstance(self.session, ba.DualTeamSession
+ ) and self._entire_team_must_finish:
+ team.lap = min([p.lap for p in team.players])
else:
- team.gamedata['lap'] = max(
- [p.gamedata['lap'] for p in team.players])
+ team.lap = max([p.lap for p in team.players])
# A player is finishing.
- if player.gamedata['lap'] == self.settings['Laps']:
+ if player.lap == self._laps:
# In teams mode, hand out points based on the order
# players come in.
@@ -275,27 +283,22 @@ class RaceGame(ba.TeamGameActivity):
# Flash where the player is.
self._flash_player(player, 1.0)
- player.gamedata['finished'] = True
+ player.finished = True
assert player.actor
player.actor.handlemessage(
ba.DieMessage(immediate=True))
# Makes sure noone behind them passes them in rank
# while finishing.
- player.gamedata['distance'] = 9999.0
+ player.distance = 9999.0
# If the whole team has finished the race.
- if team.gamedata['lap'] == self.settings['Laps']:
+ if team.lap == self._laps:
ba.playsound(self._score_sound)
- player.team.gamedata['finished'] = True
+ player.team.finished = True
assert self._timer is not None
- cur_time = ba.time(
- timeformat=ba.TimeFormat.MILLISECONDS)
- start_time = self._timer.getstarttime(
- timeformat=ba.TimeFormat.MILLISECONDS)
- self._last_team_time = (
- player.team.gamedata['time']) = (cur_time -
- start_time)
+ elapsed = ba.time() - self._timer.getstarttime()
+ self._last_team_time = player.team.time = elapsed
self._check_end_game()
# Team has yet to finish.
@@ -320,10 +323,9 @@ class RaceGame(ba.TeamGameActivity):
'torso_position', mathnode, 'input2')
tstr = ba.Lstr(resource='lapNumberText',
subs=[('${CURRENT}',
- str(player.gamedata['lap'] +
- 1)),
- ('${TOTAL}',
- str(self.settings['Laps']))])
+ str(player.lap + 1)),
+ ('${TOTAL}', str(self._laps))
+ ])
txtnode = ba.newnode('text',
owner=mathnode,
attrs={
@@ -341,77 +343,64 @@ class RaceGame(ba.TeamGameActivity):
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: ba.Team) -> None:
- team.gamedata['time'] = None
- team.gamedata['lap'] = 0
- team.gamedata['finished'] = False
+ def on_team_join(self, team: Team) -> None:
self._update_scoreboard()
- def on_player_join(self, player: ba.Player) -> None:
- player.gamedata['last_region'] = 0
- player.gamedata['lap'] = 0
- player.gamedata['distance'] = 0.0
- player.gamedata['finished'] = False
- player.gamedata['rank'] = None
- ba.TeamGameActivity.on_player_join(self, player)
-
- def on_player_leave(self, player: ba.Player) -> None:
- ba.TeamGameActivity.on_player_leave(self, player)
+ def on_player_leave(self, player: Player) -> None:
+ 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
# leading player to win).
if (isinstance(self.session, ba.DualTeamSession)
- and self.settings.get('Entire Team Must Finish')):
+ and self._entire_team_must_finish):
ba.screenmessage(ba.Lstr(
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.gamedata['finished'] = True
- player.team.gamedata['time'] = None
- player.team.gamedata['lap'] = 0
+ player.team.finished = True
+ player.team.time = None
+ player.team.lap = 0
ba.playsound(ba.getsound('boo'))
for otherplayer in player.team.players:
- otherplayer.gamedata['lap'] = 0
- otherplayer.gamedata['finished'] = True
+ otherplayer.lap = 0
+ otherplayer.finished = True
try:
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)
def _update_scoreboard(self) -> None:
for team in self.teams:
- distances = [
- player.gamedata['distance'] for player in team.players
- ]
+ distances = [player.distance for player in team.players]
if not distances:
- teams_dist = 0
+ teams_dist = 0.0
else:
if (isinstance(self.session, ba.DualTeamSession)
- and self.settings.get('Entire Team Must Finish')):
+ and self._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._laps,
+ flash=(teams_dist >= float(self._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._time_limit)
self.setup_standard_powerup_drops()
self._team_finish_pts = 100
@@ -431,16 +420,15 @@ class RaceGame(ba.TeamGameActivity):
}))
self._timer = OnScreenTimer()
- if self.settings['Mine Spawning'] != 0:
+ if self._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'],
- self._update_race_mine,
- repeat=True)
+ self._race_mine_timer = ba.Timer(0.001 * self._mine_spawning,
+ self._update_race_mine,
+ repeat=True)
self._scoreboard_timer = ba.Timer(0.25,
self._update_scoreboard,
@@ -513,33 +501,29 @@ class RaceGame(ba.TeamGameActivity):
try:
assert isinstance(player.actor, PlayerSpaz)
player.actor.connect_controls_to_player()
- except Exception as exc:
- print('Exception in race player connects:', exc)
+ except Exception:
+ ba.print_exception('Error in race player connects.')
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'],
+ if self._bomb_spawning != 0:
+ self._bomb_spawn_timer = ba.Timer(0.001 * self._bomb_spawning,
self._spawn_bomb,
repeat=True)
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.gamedata['last_region']
+ r_index = player.last_region
rg1 = self._regions[r_index]
r1pt = ba.Vec3(rg1.pos[:3])
rg2 = self._regions[0] if r_index == len(
@@ -547,25 +531,19 @@ class RaceGame(ba.TeamGameActivity):
r2pt = ba.Vec3(rg2.pos[:3])
r2dist = (pos - r2pt).length()
amt = 1.0 - (r2dist / (r2pt - r1pt).length())
- amt = player.gamedata['lap'] + (r_index + amt) * (
- 1.0 / len(self._regions))
- player.gamedata['distance'] = amt
+ amt = player.lap + (r_index + amt) * (1.0 / len(self._regions))
+ player.distance = amt
# Sort players by distance and update their ranks.
- p_list = [[player.gamedata['distance'], player]
- for player in self.players]
+ p_list = [(player.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:
- # noinspection PyUnresolvedReferences
- node = plr[1].actor.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:
@@ -622,13 +600,14 @@ class RaceGame(ba.TeamGameActivity):
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:
- if player.team.gamedata['finished']:
- # FIXME: This is not type-safe
- # (this call is expected to return an Actor).
+ def spawn_player(self, player: Player) -> ba.Actor:
+ if player.team.finished:
+ # 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
+ pos = self._regions[player.last_region].pos
# Don't use the full region so we're less likely to spawn off a cliff.
region_scale = 0.8
@@ -663,26 +642,21 @@ class RaceGame(ba.TeamGameActivity):
'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
def _check_end_game(self) -> None:
# If there's no teams left racing, finish.
- teams_still_in = len(
- [t for t in self.teams if not t.gamedata['finished']])
+ teams_still_in = len([t for t in self.teams if not t.finished])
if teams_still_in == 0:
self.end_game()
return
# Count the number of teams that have completed the race.
- teams_completed = len([
- t for t in self.teams
- if t.gamedata['finished'] and t.gamedata['time'] is not None
- ])
+ teams_completed = len(
+ [t for t in self.teams if t.finished and t.time is not None])
if teams_completed > 0:
session = self.session
@@ -707,22 +681,21 @@ class RaceGame(ba.TeamGameActivity):
# Stop updating our time text, and set it to show the exact last
# finish time if we have one. (so users don't get upset if their
- # final time differs from what they see onscreen by a tiny bit)
+ # final time differs from what they see onscreen by a tiny amount)
assert self._timer is not None
if self._timer.has_started():
- cur_time = self._timer.getstarttime(
- timeformat=ba.TimeFormat.MILLISECONDS)
self._timer.stop(
endtime=None if self._last_team_time is None else (
- cur_time + self._last_team_time))
+ self._timer.getstarttime() + self._last_team_time))
- results = ba.TeamGameResults()
+ results = ba.GameResults()
for team in self.teams:
- if team.gamedata['time'] is not None:
- results.set_team_score(team, team.gamedata['time'])
- # If game have ended before we
- # get any result, use 'fail' screen
+ if team.time is not None:
+ # We store time in seconds, but pass a score in milliseconds.
+ results.set_team_score(team, int(team.time * 1000.0))
+ else:
+ results.set_team_score(team, None)
# We don't announce a winner in ffa mode since its probably been a
# while since the first place guy crossed the finish line so it seems
@@ -732,14 +705,11 @@ class RaceGame(ba.TeamGameActivity):
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.spaz.getplayer()
- if not player:
- ba.print_error('got no player in PlayerSpazDeathMessage')
- return
- if not player.gamedata['finished']:
+ player = msg.getplayer(Player)
+ if not player.finished:
self.respawn_player(player, respawn_time=1)
else:
super().handlemessage(msg)
diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py
index 013e4abf..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.
@@ -26,56 +8,112 @@
from __future__ import annotations
import random
+from dataclasses import dataclass
+from enum import Enum
from typing import TYPE_CHECKING
import ba
-from bastd.actor import playerspaz
-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.gameutils import SharedObjects
+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
+ from typing import Type, Any, List, Dict, Tuple, Sequence, Optional, Union
-class RunaroundGame(ba.CoopGameActivity):
+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 event."""
+ 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']):
+ """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."""
+
+
+class RunaroundGame(ba.CoopGameActivity[Player, 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.',
'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 = {
- 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
}
- @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]):
+ def __init__(self, settings: dict):
settings['map'] = 'Tower D'
super().__init__(settings)
- self._preset = self.settings.get('preset', 'pro')
+ shared = SharedObjects.get()
+ self._preset = Preset(settings.get('preset', 'pro'))
self._player_death_sound = ba.getsound('playerDeath')
self._new_wave_sound = ba.getsound('scoreHit01')
@@ -96,16 +134,18 @@ class RunaroundGame(ba.CoopGameActivity):
self._score_region_material = ba.Material()
self._score_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', self._handle_reached_end)))
+ 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),
+ ))
self._last_wave_end_time = ba.time()
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
@@ -114,8 +154,8 @@ class RunaroundGame(ba.CoopGameActivity):
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._bots = spazbot.BotSet()
+ self._waves: Optional[List[Wave]] = None
+ self._bots = SpazBotSet()
self._tntspawner: Optional[TNTSpawner] = None
self._lives_bg: Optional[ba.NodeActor] = None
self._start_lives = 10
@@ -130,7 +170,6 @@ class RunaroundGame(ba.CoopGameActivity):
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)
@@ -147,206 +186,186 @@ class RunaroundGame(ba.CoopGameActivity):
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': 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
- else None,
- {'type': spazbot.BomberBot, 'path': 1} if hard else None,
- {'type': spazbot.BomberBot, 'path': 1} if player_count > 2
- else None,
- {'type': spazbot.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
- 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
- else None,
- {'type': spazbot.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
- else None,
- {'type': spazbot.TriggerBot, 'path': 2},
- {'type': spazbot.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
- else None,
- ]},
- {'entries': [
- {'type': spazbot.TriggerBot, 'path': 1} if hard else None,
- {'type': 'spacing', 'duration': 1.0} if hard else None,
- {'type': spazbot.TriggerBot, 'path': 2},
- {'type': 'spacing', 'duration': 1.0},
- {'type': spazbot.TriggerBot, 'path': 3},
- {'type': 'spacing', 'duration': 1.0},
- {'type': spazbot.TriggerBot, 'path': 1} if hard else None,
- {'type': 'spacing', 'duration': 1.0} if hard else None,
- {'type': spazbot.TriggerBot, 'path': 2},
- {'type': 'spacing', 'duration': 1.0},
- {'type': spazbot.TriggerBot, 'path': 3},
- {'type': 'spacing', 'duration': 1.0},
- {'type': spazbot.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
- else None,
- {'type': 'spacing', 'duration': 1.0},
- {'type': spazbot.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
- else None,
- {'type': spazbot.BrawlerBot, 'path': 3} if player_count > 2
- else None,
- {'type': spazbot.BrawlerBot, 'path': 3} if player_count > 3
- else None,
- ]},
- {'entries': [
- {'type': spazbot.BomberBotProShielded, 'path': 3},
- {'type': 'spacing', 'duration': 1.5},
- {'type': spazbot.BomberBotProShielded, 'path': 2},
- {'type': 'spacing', 'duration': 1.5},
- {'type': spazbot.BomberBotProShielded, 'path': 1} if hard
- else None,
- {'type': 'spacing', 'duration': 1.0} if hard else None,
- {'type': spazbot.BomberBotProShielded, 'path': 3},
- {'type': 'spacing', 'duration': 1.5},
- {'type': spazbot.BomberBotProShielded, 'path': 2},
- {'type': 'spacing', 'duration': 1.5},
- {'type': spazbot.BomberBotProShielded, 'path': 1} if hard
- else None,
- {'type': 'spacing', 'duration': 1.5} if hard else None,
- {'type': spazbot.BomberBotProShielded, 'path': 3}
- if player_count > 1 else None,
- {'type': 'spacing', 'duration': 1.5},
- {'type': spazbot.BomberBotProShielded, 'path': 2}
- if player_count > 2 else None,
- {'type': 'spacing', 'duration': 1.5},
- {'type': spazbot.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': 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'}
- 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
- else None,
- ]},
- {'entries': [
- {'type': spazbot.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'}
- if player_count > 2 else None,
- ]},
- {'entries': [
- {'type': spazbot.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}
- if player_count > 1 else None,
- {'type': spazbot.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,
- 'point': 'bottom_right'}
- if hard else None,
- {'type': spazbot.TriggerBotProShielded,
- 'point': 'bottom_right'}
- if player_count > 2 else None,
- {'type': spazbot.BomberBot, 'path': 3},
- {'type': spazbot.BomberBot, 'path': 3},
- {'type': 'spacing', 'duration': 5.0},
- {'type': spazbot.BrawlerBot, 'path': 2},
- {'type': spazbot.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,
- ]},
- {'entries': [
- {'type': spazbot.BomberBotProShielded, 'path': 2},
- {'type': spazbot.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'}
- 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}
- if player_count > 1 else None,
- {'type': 'spacing', 'duration': 5.0},
- {'type': spazbot.StickyBot, 'point': 'bottom_left'},
- {'type': 'spacing', 'duration': 2.0},
- {'type': spazbot.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
@@ -361,9 +380,9 @@ class RunaroundGame(ba.CoopGameActivity):
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.ui.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',
@@ -398,9 +417,7 @@ class RunaroundGame(ba.CoopGameActivity):
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().opposingnode.getdelegate(SpazBot, True)
if not spaz.is_alive():
return # Ignore bodies flying in.
@@ -463,12 +480,12 @@ class RunaroundGame(ba.CoopGameActivity):
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))
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.
@@ -480,12 +497,11 @@ class RunaroundGame(ba.CoopGameActivity):
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)
@@ -493,8 +509,7 @@ class RunaroundGame(ba.CoopGameActivity):
def _drop_powerups(self,
standard_points: bool = False,
force_first: str = None) -> None:
- """ Generic powerup drop """
- from bastd.actor import powerupbox
+ """Generic powerup drop."""
# If its been a minute since our last wave finished emerging, stop
# giving out land-mine powerups. (prevents players from waiting
@@ -520,21 +535,13 @@ class RunaroundGame(ba.CoopGameActivity):
# 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()
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)
@@ -549,7 +556,7 @@ class RunaroundGame(ba.CoopGameActivity):
delay = 0
score: Optional[int]
- if self._wave >= 2:
+ if self._wavenum >= 2:
score = self._score
fail_message = None
else:
@@ -561,7 +568,7 @@ class RunaroundGame(ba.CoopGameActivity):
'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:
@@ -578,11 +585,11 @@ class RunaroundGame(ba.CoopGameActivity):
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))
+ won = (self._wavenum == len(self._waves))
# Reward time bonus.
base_delay = 4.0 if won else 0
@@ -593,7 +600,7 @@ class RunaroundGame(ba.CoopGameActivity):
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
@@ -602,7 +609,7 @@ class RunaroundGame(ba.CoopGameActivity):
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:
@@ -610,7 +617,7 @@ class RunaroundGame(ba.CoopGameActivity):
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:
@@ -635,69 +642,60 @@ class RunaroundGame(ba.CoopGameActivity):
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
@@ -716,7 +714,7 @@ class RunaroundGame(ba.CoopGameActivity):
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)
@@ -724,55 +722,52 @@ class RunaroundGame(ba.CoopGameActivity):
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']:
- level = self._wave
+ 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 = []
- spaz_types: List[Tuple[Type[spazbot.SpazBot], float]] = []
+ entries: List[Union[Spawn, Spacing, None]] = []
+ 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):
@@ -820,15 +815,12 @@ class RunaroundGame(ba.CoopGameActivity):
elif path == 6:
this_target_point_s *= 0.7
- def _add_defender(defender_type: Tuple[Type[spazbot.SpazBot],
- float],
- pnt: str) -> Tuple[float, Dict[str, Any]]:
- # FIXME: should look into this warning
+ def _add_defender(defender_type: Tuple[Type[SpazBot], float],
+ 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(
@@ -840,10 +832,10 @@ class RunaroundGame(ba.CoopGameActivity):
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(
@@ -857,12 +849,9 @@ class RunaroundGame(ba.CoopGameActivity):
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)
@@ -877,15 +866,15 @@ class RunaroundGame(ba.CoopGameActivity):
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._wave - 1]
+ 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
@@ -893,36 +882,27 @@ class RunaroundGame(ba.CoopGameActivity):
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
@@ -964,15 +944,13 @@ class RunaroundGame(ba.CoopGameActivity):
# 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
- 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)))))
- ])
+ 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 {
+ Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT
+ } else f'/{totalwaves}'))])
self._wave_text = ba.NodeActor(
ba.newnode('text',
attrs={
@@ -988,32 +966,32 @@ class RunaroundGame(ba.CoopGameActivity):
'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,
- 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)
@@ -1035,7 +1013,7 @@ class RunaroundGame(ba.CoopGameActivity):
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:
@@ -1046,7 +1024,7 @@ class RunaroundGame(ba.CoopGameActivity):
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
@@ -1056,8 +1034,8 @@ class RunaroundGame(ba.CoopGameActivity):
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
@@ -1123,37 +1101,30 @@ class RunaroundGame(ba.CoopGameActivity):
self._score += msg.score
self._update_scores()
- # Respawn dead players.
- elif isinstance(msg, playerspaz.PlayerSpazDeathMessage):
- from bastd.actor import respawnicon
+ elif isinstance(msg, ba.PlayerDiedMessage):
+ # Augment standard behavior.
+ super().handlemessage(msg)
+
self._a_player_has_been_killed = True
- player = msg.spaz.getplayer()
- if player is None:
- ba.print_error('FIXME: getplayer() should no'
- ' longer ever be returning None')
- return
- if not player:
- return
- self.stats.player_was_killed(player)
# 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 = msg.getplayer(Player)
+ 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.gamedata['respawn_icon'] = respawnicon.RespawnIcon(
- player, respawn_time)
+ player.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)
+ 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
@@ -1168,8 +1139,8 @@ class RunaroundGame(ba.CoopGameActivity):
ba.playsound(self._dingsound if importance == 1 else
self._dingsoundhigh,
volume=0.6)
- except Exception as exc:
- print('EXC in Runaround on SpazBotDeathMessage:', 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.
@@ -1178,12 +1149,13 @@ class RunaroundGame(ba.CoopGameActivity):
self._update_scores()
else:
- super().handlemessage(msg)
+ return super().handlemessage(msg)
+ return None
- 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 Exception('Invalid bot type to _get_bot_speed(): ' +
+ raise TypeError('Invalid bot type to _get_bot_speed(): ' +
str(bot_type))
return speed
diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py
index e6c7be7e..91d0e131 100644
--- a/assets/src/ba_data/python/bastd/game/targetpractice.py
+++ b/assets/src/ba_data/python/bastd/game/targetpractice.py
@@ -1,27 +1,9 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags)
+# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
@@ -29,25 +11,42 @@ import random
from typing import TYPE_CHECKING
import ba
-from bastd.actor import playerspaz
+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, Tuple, Sequence
- from bastd.actor.onscreencountdown import OnScreenCountdown
- from bastd.actor.bomb import Bomb, Blast
+ from typing import Any, Type, List, Dict, Optional, Sequence
+ from bastd.actor.bomb import Blast
+
+
+class Player(ba.Player['Team']):
+ """Our player type for this game."""
+
+ def __init__(self) -> None:
+ self.streak = 0
+
+
+class Team(ba.Team[Player]):
+ """Our team type for this game."""
+
+ def __init__(self) -> None:
+ self.score = 0
# ba_meta export game
-class TargetPracticeGame(ba.TeamGameActivity):
+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.'
+ 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
@classmethod
def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]:
@@ -59,64 +58,46 @@ class TargetPracticeGame(ba.TeamGameActivity):
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
+ def __init__(self, settings: dict):
super().__init__(settings)
self._scoreboard = Scoreboard()
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:
- 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()
def on_begin(self) -> None:
- from bastd.actor.onscreencountdown import OnScreenCountdown
super().on_begin()
self.update_scoreboard()
# Number of targets is based on player count.
- num_targets = self.settings['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['Enable Impact Bombs']:
+ if self._enable_impact_bombs:
spaz.bomb_type = 'impact'
- if self.settings['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
@@ -134,9 +115,9 @@ class TargetPracticeGame(ba.TeamGameActivity):
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
@@ -150,7 +131,6 @@ class TargetPracticeGame(ba.TeamGameActivity):
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)
@@ -166,17 +146,18 @@ class TargetPracticeGame(ba.TeamGameActivity):
# 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 = 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)
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."""
@@ -185,9 +166,9 @@ class TargetPracticeGame(ba.TeamGameActivity):
def handlemessage(self, msg: Any) -> Any:
# When players die, respawn them.
- if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
+ if isinstance(msg, ba.PlayerDiedMessage):
super().handlemessage(msg) # Do standard stuff.
- player = msg.spaz.getplayer()
+ player = msg.getplayer(Player)
assert player is not None
self.respawn_player(player) # Kick off a respawn.
elif isinstance(msg, Target.TargetHitMessage):
@@ -200,12 +181,12 @@ class TargetPracticeGame(ba.TeamGameActivity):
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()
+ results = ba.GameResults()
for team in self.teams:
- results.set_team_score(team, team.gamedata['score'])
+ results.set_team_score(team, team.score)
self.end(results)
@@ -274,15 +255,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: 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
activity = self.activity
# Ignore hits if the game is over or if we've already been hit
@@ -316,7 +295,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:
@@ -350,14 +329,14 @@ 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()
- popuptext.PopupText(popupstr,
- position=self._position,
- color=popupcolor,
- scale=popupscale).autoretain()
+ popupstr += ' ' + player.getname()
+ PopupText(popupstr,
+ position=self._position,
+ color=popupcolor,
+ 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 0bb069c3..5a24cc4d 100644
--- a/assets/src/ba_data/python/bastd/game/thelaststand.py
+++ b/assets/src/ba_data/python/bastd/game/thelaststand.py
@@ -1,66 +1,67 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
import random
+from dataclasses import dataclass
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
+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.scoreboard import Scoreboard
+ from bastd.actor.spazbot import SpazBot
-class TheLastStandGame(ba.CoopGameActivity):
+@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."""
+
+
+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."""
+ 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]):
+ default_music = ba.MusicType.EPIC
+
+ def __init__(self, settings: dict):
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')
@@ -68,11 +69,11 @@ 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 = str(settings.get('preset', 'default'))
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
@@ -80,25 +81,23 @@ class TheLastStandGame(ba.CoopGameActivity):
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 = {
- 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: 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:
- 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'),
@@ -113,12 +112,10 @@ class TheLastStandGame(ba.CoopGameActivity):
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)
- 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))
@@ -136,12 +133,11 @@ class TheLastStandGame(ba.CoopGameActivity):
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,
@@ -170,7 +166,7 @@ class TheLastStandGame(ba.CoopGameActivity):
# 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:
@@ -181,7 +177,7 @@ class TheLastStandGame(ba.CoopGameActivity):
results={
'outcome': outcome,
'score': self._score,
- 'player_info': self.initial_player_info
+ 'playerinfos': self.initialplayerinfos
})
def _update_bots(self) -> None:
@@ -197,17 +193,15 @@ class TheLastStandGame(ba.CoopGameActivity):
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])
-
- # 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]:
@@ -220,17 +214,17 @@ class TheLastStandGame(ba.CoopGameActivity):
# 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.SpazBot]] = None
- for spawntype in self._bot_spawn_types.items():
- total += spawntype[1][0]
+ bottype: Optional[Type[SpazBot]] = None
+ 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
@@ -238,13 +232,14 @@ class TheLastStandGame(ba.CoopGameActivity):
# 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:
- # 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')
@@ -256,14 +251,8 @@ class TheLastStandGame(ba.CoopGameActivity):
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.spaz.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)
@@ -271,28 +260,21 @@ class TheLastStandGame(ba.CoopGameActivity):
self._score += msg.score
self._update_scores()
- elif isinstance(msg, spazbot.SpazBotDeathMessage):
- pts, importance = msg.badguy.get_death_points(msg.how)
+ elif isinstance(msg, SpazBotDiedMessage):
+ pts, importance = msg.spazbot.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.spazbot.node
+ target = msg.spazbot.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.
@@ -303,7 +285,6 @@ class TheLastStandGame(ba.CoopGameActivity):
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/assets/src/ba_data/python/bastd/gameutils.py b/assets/src/ba_data/python/bastd/gameutils.py
new file mode 100644
index 00000000..280e5742
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/gameutils.py
@@ -0,0 +1,145 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Various utilities useful for gameplay."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import ba
+
+if TYPE_CHECKING:
+ from typing import Sequence, Optional
+
+
+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.
+ """
+
+ _STORENAME = ba.storagename()
+
+ def __init__(self) -> None:
+ activity = ba.getactivity()
+ 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
+ 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
+
+ @classmethod
+ def get(cls) -> SharedObjects:
+ """Fetch/create the instance of this class for the current activity."""
+ activity = ba.getactivity()
+ shobs = activity.customdata.get(cls._STORENAME)
+ if shobs is None:
+ shobs = SharedObjects()
+ activity.customdata[cls._STORENAME] = 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/keyboard/__init__.py b/assets/src/ba_data/python/bastd/keyboard/__init__.py
new file mode 100644
index 00000000..867b1714
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/keyboard/__init__.py
@@ -0,0 +1 @@
+# Released under the MIT License. See LICENSE for details.
diff --git a/assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py b/assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py
new file mode 100644
index 00000000..a7e197d2
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py
@@ -0,0 +1,55 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""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, 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, ...]] = {
+ f'emoji{i}': tuple(page)
+ for i, page in enumerate(generate_emojis(len(nums)))
+ }
diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py
index ff81f237..5889631a 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
@@ -27,9 +9,8 @@ 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 +24,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')
@@ -64,9 +45,10 @@ class MainMenuActivity(ba.Activity):
if not ba.app.toolbar_test:
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.ui.uiscale is ba.UIScale.SMALL or vr_mode) else 0.7)
self.my_name = ba.NodeActor(
ba.newnode('text',
attrs={
@@ -78,7 +60,7 @@ class MainMenuActivity(ba.Activity):
'scale': scale,
'position': (0, 10),
'vr_depth': -10,
- 'text': '\xa9 2011-2020 Eric Froemling'
+ 'text': '\xa9 2011-2021 Eric Froemling'
}))
# Throw up some text that only clients can see so they know that the
@@ -105,7 +87,7 @@ class MainMenuActivity(ba.Activity):
# 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.ui.uiscale
# In cases where we're doing lots of dev work lets always show the
# build number.
@@ -128,7 +110,7 @@ class MainMenuActivity(ba.Activity):
])
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(
@@ -149,10 +131,29 @@ class MainMenuActivity(ba.Activity):
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.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={
@@ -182,7 +183,7 @@ class MainMenuActivity(ba.Activity):
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)
@@ -319,7 +320,8 @@ class MainMenuActivity(ba.Activity):
transition_out_delay=self._message_duration
).autoretain()
achs = [
- a for a in app.achievements if not a.complete
+ a for a in app.ach.achievements
+ if not a.complete
]
if achs:
ach = achs.pop(
@@ -358,7 +360,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):
@@ -374,7 +376,7 @@ class MainMenuActivity(ba.Activity):
ba.WeakCall(self._change_phrase),
repeat=True)
- scl = 1.2 if (ba.app.interface_type == '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
@@ -397,62 +399,65 @@ class MainMenuActivity(ba.Activity):
}))
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.
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:
+ if ba.app.demo_mode or ba.app.arcade_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
@@ -489,7 +494,7 @@ class MainMenuActivity(ba.Activity):
ba.getmodel('logoTransparent'))
# If language has changed, recreate our logo text/graphics.
- lang = app.language
+ lang = app.lang.language
if lang != self._language:
self._language = lang
y = 20
@@ -508,11 +513,11 @@ class MainMenuActivity(ba.Activity):
# We draw higher in kiosk mode (make sure to test this
# when making adjustments) for now we're hard-coded for
# a few languages.. should maybe look into generalizing this?..
- if app.language == 'Chinese':
+ if app.lang.language == 'Chinese':
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,
@@ -565,7 +570,7 @@ class MainMenuActivity(ba.Activity):
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):
@@ -830,7 +835,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()
@@ -858,8 +863,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)
@@ -880,12 +885,13 @@ 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)
def _preload3() -> None:
+ from bastd.actor.spazfactory import SpazFactory
for mname in ['bomb', 'bombSticky', 'impactBomb']:
ba.getmodel(mname)
for tname in [
@@ -895,7 +901,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)
@@ -906,8 +912,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):
@@ -920,15 +926,15 @@ class MainMenuSession(ba.Session):
super().__init__([self._activity_deps])
self._locked = False
- self.set_activity(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.set_activity(ba.new_activity(MainMenuActivity))
+ self.setactivity(ba.newactivity(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/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/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 aa467779..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
@@ -26,7 +8,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
@@ -35,7 +17,6 @@ if TYPE_CHECKING:
class HockeyStadium(ba.Map):
"""Stadium map used for ice hockey games."""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import hockey_stadium as defs
name = 'Hockey Stadium'
@@ -66,6 +47,7 @@ class HockeyStadium(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode('terrain',
delegate=self,
attrs={
@@ -76,7 +58,7 @@ class HockeyStadium(ba.Map):
'color_texture':
self.preloaddata['tex'],
'materials': [
- ba.sharedobj('footing_material'),
+ shared.footing_material,
self.preloaddata['ice_material']
]
})
@@ -88,9 +70,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],
@@ -106,7 +86,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
@@ -146,6 +126,7 @@ class FootballStadium(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -153,7 +134,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={
@@ -163,7 +144,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)
@@ -183,7 +164,6 @@ class FootballStadium(ba.Map):
class Bridgit(ba.Map):
"""Map with a narrow bridge in the middle."""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import bridgit as defs
name = 'Bridgit'
@@ -220,6 +200,7 @@ class Bridgit(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -227,7 +208,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={
@@ -255,7 +236,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',
@@ -263,12 +244,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)
@@ -278,7 +259,6 @@ class Bridgit(ba.Map):
class BigG(ba.Map):
"""Large G shaped map for racing"""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import big_g as defs
name = 'Big G'
@@ -315,6 +295,7 @@ class BigG(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -323,7 +304,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={
@@ -352,7 +333,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',
@@ -360,12 +341,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)
@@ -375,7 +356,6 @@ class BigG(ba.Map):
class Roundabout(ba.Map):
"""CTF map featuring two platforms and a long way around between them"""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import roundabout as defs
name = 'Roundabout'
@@ -410,6 +390,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,
@@ -417,7 +398,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={
@@ -446,19 +427,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
@@ -469,7 +450,6 @@ class Roundabout(ba.Map):
class MonkeyFace(ba.Map):
"""Map sorta shaped like a monkey face; teehee!"""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import monkey_face as defs
name = 'Monkey Face'
@@ -504,6 +484,7 @@ class MonkeyFace(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -511,7 +492,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={
@@ -540,19 +521,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)
@@ -563,7 +544,6 @@ class MonkeyFace(ba.Map):
class ZigZag(ba.Map):
"""A very long zig-zaggy map"""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import zig_zag as defs
name = 'Zigzag'
@@ -599,6 +579,7 @@ class ZigZag(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -606,7 +587,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',
@@ -634,19 +615,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)
@@ -657,7 +638,6 @@ class ZigZag(ba.Map):
class ThePad(ba.Map):
"""A simple square shaped map with a raised edge."""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import the_pad as defs
name = 'The Pad'
@@ -689,6 +669,7 @@ class ThePad(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -696,7 +677,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={
@@ -716,7 +697,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',
@@ -728,7 +709,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)
@@ -736,9 +717,8 @@ class ThePad(ba.Map):
class DoomShroom(ba.Map):
- """A giant mushroom. Of doom."""
+ """A giant mushroom. Of doom!"""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import doom_shroom as defs
name = 'Doom Shroom'
@@ -768,6 +748,7 @@ class DoomShroom(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -775,7 +756,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',
@@ -799,16 +780,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
@@ -831,7 +809,6 @@ class DoomShroom(ba.Map):
class LakeFrigid(ba.Map):
"""An icy lake fit for racing."""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import lake_frigid as defs
name = 'Lake Frigid'
@@ -863,6 +840,7 @@ class LakeFrigid(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode('terrain',
delegate=self,
attrs={
@@ -873,7 +851,7 @@ class LakeFrigid(ba.Map):
'color_texture':
self.preloaddata['tex'],
'materials': [
- ba.sharedobj('footing_material'),
+ shared.footing_material,
self.preloaddata['ice_material']
]
})
@@ -899,7 +877,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
@@ -912,7 +890,6 @@ class LakeFrigid(ba.Map):
class TipTop(ba.Map):
"""A pointy map good for king-of-the-hill-ish games."""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import tip_top as defs
name = 'Tip Top'
@@ -941,6 +918,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,
@@ -949,7 +927,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={
@@ -971,10 +949,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)
@@ -984,7 +962,6 @@ class TipTop(ba.Map):
class CragCastle(ba.Map):
"""A lovely castle map."""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import crag_castle as defs
name = 'Crag Castle'
@@ -1017,6 +994,7 @@ class CragCastle(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -1024,7 +1002,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={
@@ -1044,7 +1022,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',
@@ -1056,7 +1034,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)
@@ -1117,6 +1095,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,
@@ -1124,7 +1103,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',
@@ -1158,7 +1137,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)
@@ -1185,7 +1164,6 @@ class TowerD(ba.Map):
class HappyThoughts(ba.Map):
"""Flying map."""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import happy_thoughts as defs
name = 'Happy Thoughts'
@@ -1221,6 +1199,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,
@@ -1228,7 +1207,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={
@@ -1253,7 +1232,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)
@@ -1291,7 +1270,6 @@ class HappyThoughts(ba.Map):
class StepRightUp(ba.Map):
"""Wide stepped map good for CTF or Assault."""
- # noinspection PyUnresolvedReferences
from bastd.mapdata import step_right_up as defs
name = 'Step Right Up'
@@ -1322,6 +1300,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,
@@ -1329,7 +1308,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',
@@ -1356,7 +1335,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)
@@ -1407,6 +1386,7 @@ class Courtyard(ba.Map):
def __init__(self) -> None:
super().__init__()
+ shared = SharedObjects.get()
self.node = ba.newnode(
'terrain',
delegate=self,
@@ -1414,7 +1394,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',
@@ -1450,7 +1430,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)
@@ -1502,6 +1482,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,
@@ -1509,7 +1490,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',
@@ -1544,10 +1525,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/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/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 ff912995..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;
@@ -28,8 +10,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,9 +163,23 @@ class ButtonRelease:
timeformat=ba.TimeFormat.MILLISECONDS)
-class TutorialActivity(ba.Activity):
+class Player(ba.Player['Team']):
+ """Our player type for this game."""
- def __init__(self, settings: Dict[str, Any] = None):
+ 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 = None):
from bastd.maps import Rampage
if settings is None:
settings = {}
@@ -225,7 +221,6 @@ class TutorialActivity(ba.Activity):
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] = []
@@ -386,9 +381,6 @@ class TutorialActivity(ba.Activity):
]
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:
@@ -462,6 +454,7 @@ class TutorialActivity(ba.Activity):
n.opacity = 0.0
a.set_stick_image_position(0, 0)
+ # Can be used for debugging.
class SetSpeed:
def __init__(self, speed: int):
@@ -829,7 +822,7 @@ class TutorialActivity(ba.Activity):
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),
@@ -2294,8 +2287,7 @@ class TutorialActivity(ba.Activity):
]
except Exception:
- import traceback
- traceback.print_exc()
+ ba.print_exception()
# If we read some, exec them.
if self._entries:
@@ -2313,8 +2305,7 @@ class TutorialActivity(ba.Activity):
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.
@@ -2330,7 +2321,7 @@ class TutorialActivity(ba.Activity):
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 +2340,7 @@ class TutorialActivity(ba.Activity):
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 +2354,7 @@ class TutorialActivity(ba.Activity):
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 +2367,7 @@ class TutorialActivity(ba.Activity):
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 +2384,16 @@ class TutorialActivity(ba.Activity):
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..
- player.assign_input_call(
- ('jumpPress', 'punchPress', 'bombPress', 'pickUpPress'),
+
+ # We just wanna know if this player presses anything.
+ player.assigninput(
+ (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: 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/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 f25a3509..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
@@ -49,14 +31,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.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(
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),
@@ -76,7 +59,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')
@@ -131,11 +114,13 @@ class AccountLinkCodeWindow(ba.Window):
def __init__(self, data: Dict[str, Any]):
self._width = 350
self._height = 200
+ uiscale = ba.app.ui.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 3bbd23f9..785f186e 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
@@ -77,11 +59,12 @@ class AccountSettingsWindow(ba.Window):
self._can_reset_achievements = (account_type == 'Game Center')
app = ba.app
+ uiscale = app.ui.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 +86,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.ui.use_toolbars:
self._back_button = None
ba.containerwidget(edit=self._root_widget,
on_cancel_call=self._back)
@@ -138,7 +122,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')
@@ -148,7 +132,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()
@@ -320,15 +307,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
@@ -361,7 +343,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')
@@ -448,7 +430,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)
@@ -473,7 +455,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)
@@ -497,7 +479,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)
@@ -543,7 +525,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)
@@ -590,7 +572,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)
@@ -612,7 +594,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)
@@ -627,8 +609,8 @@ class AccountSettingsWindow(ba.Window):
elif account_type == 'Game Circle':
account_type_name = ba.Lstr(resource='gameCircleText')
else:
- raise Exception("unknown account type: '" + str(account_type) +
- "'")
+ raise ValueError("unknown account type: '" +
+ str(account_type) + "'")
self._game_service_button = btn = ba.buttonwidget(
parent=self._subcontainer,
position=((self._sub_width - button_width) * 0.5, v),
@@ -640,7 +622,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)
@@ -682,7 +664,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)
@@ -710,7 +692,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)
@@ -780,7 +762,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)
@@ -835,7 +817,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)
@@ -863,7 +845,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)
@@ -884,7 +866,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)
@@ -968,13 +950,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;
@@ -984,7 +966,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:
@@ -1013,8 +995,8 @@ class AccountSettingsWindow(ba.Window):
if (self._achievements_text is None
and self._achievements_button is None):
return
- complete = sum(1 if a.complete else 0 for a in ba.app.achievements)
- total = len(ba.app.achievements)
+ complete = sum(1 if a.complete else 0 for a in ba.app.ach.achievements)
+ total = len(ba.app.ach.achievements)
txt_final = ba.Lstr(resource=self._r + '.achievementProgressText',
subs=[('${COUNT}', str(complete)),
('${TOTAL}', str(total))])
@@ -1071,31 +1053,31 @@ 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')
+ ba.print_exception('Error resetting co-op campaign progress.')
ba.playsound(ba.getsound('shieldDown'))
self._refresh()
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:
@@ -1105,17 +1087,14 @@ class AccountSettingsWindow(ba.Window):
elif sel == self._scrollwidget:
sel_name = 'Scroll'
else:
- raise Exception('unrecognized selection')
- ba.app.window_states[self.__class__.__name__] = sel_name
+ raise ValueError('unrecognized selection')
+ ba.app.ui.window_states[type(self)] = 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.ui.window_states.get(type(self))
if sel_name == 'Back':
sel = self._back_button
elif sel_name == 'Scroll':
@@ -1124,4 +1103,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/unlink.py b/assets/src/ba_data/python/bastd/ui/account/unlink.py
index 7d20768a..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
@@ -50,14 +32,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.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(
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),
@@ -76,7 +59,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,
@@ -90,6 +73,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/account/viewer.py b/assets/src/ba_data/python/bastd/ui/account/viewer.py
index 5aaa952c..a8ea39af 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
@@ -41,18 +23,20 @@ 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
+ uiscale = ba.app.ui.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)
@@ -124,12 +108,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:
@@ -159,9 +143,11 @@ class AccountViewerWindow(popup.PopupWindow):
choices.append('ban')
choices_display.append(ba.Lstr(resource='banThisPlayerText'))
+ uiscale = ba.app.ui.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',
@@ -208,7 +194,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 +241,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),
@@ -288,7 +274,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
@@ -315,7 +301,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
@@ -429,7 +415,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
@@ -440,7 +426,7 @@ class AccountViewerWindow(popup.PopupWindow):
v_align='center',
scale=0.55,
text=str(data['achievementsCompleted']) + ' / ' +
- str(len(ba.app.achievements)),
+ str(len(ba.app.ach.achievements)),
maxwidth=sub_width * maxwidth_scale)
v -= 25
@@ -458,7 +444,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'),
@@ -474,7 +460,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/achievements.py b/assets/src/ba_data/python/bastd/ui/achievements.py
index 2583a086..ca56c436 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
@@ -36,13 +18,14 @@ class AchievementsWindow(popup.PopupWindow):
def __init__(self, position: Tuple[float, float], scale: float = None):
# pylint: disable=too-many-locals
+ uiscale = ba.app.ui.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
@@ -64,7 +47,7 @@ class AchievementsWindow(popup.PopupWindow):
icon=ba.gettexture('crossOut'),
iconscale=1.2)
- achievements = ba.app.achievements
+ achievements = ba.app.ach.achievements
num_complete = len([a for a in achievements if a.complete])
txt_final = ba.Lstr(
diff --git a/assets/src/ba_data/python/bastd/ui/appinvite.py b/assets/src/ba_data/python/bastd/ui/appinvite.py
index a043192f..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
@@ -42,10 +24,12 @@ class AppInviteWindow(ba.Window):
self._width = 650
self._height = 400
+ uiscale = ba.app.ui.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 +156,13 @@ class ShowFriendCodeWindow(ba.Window):
ba.set_analytics_screen('Friend Promo Code')
self._width = 650
self._height = 400
+ uiscale = ba.app.ui.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'))
@@ -198,7 +184,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',
@@ -227,7 +213,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/characterpicker.py b/assets/src/ba_data/python/bastd/ui/characterpicker.py
index 40cbe68d..6f57a20b 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
@@ -48,9 +30,10 @@ class CharacterPicker(popup.PopupWindow):
# pylint: disable=too-many-locals
from bastd.actor import spazappearance
del parent # unused here
+ uiscale = ba.app.ui.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 +62,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
@@ -170,16 +154,15 @@ class CharacterPicker(popup.PopupWindow):
ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)
def _on_store_press(self) -> None:
- 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._transition_out()
- browser.StoreBrowserWindow(
- modal=True,
- show_tab='characters',
- origin_widget=self._get_more_characters_button)
+ StoreBrowserWindow(modal=True,
+ show_tab=StoreBrowserWindow.TabID.CHARACTERS,
+ origin_widget=self._get_more_characters_button)
def _select_character(self, character: str) -> None:
if self._delegate is not None:
diff --git a/assets/src/ba_data/python/bastd/ui/colorpicker.py b/assets/src/ba_data/python/bastd/ui/colorpicker.py
index 53856e28..b9630a25 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
@@ -25,13 +7,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.
@@ -46,16 +28,16 @@ class ColorPicker(popup.PopupWindow):
offset: Tuple[float, float] = (0.0, 0.0),
tag: Any = ''):
# pylint: disable=too-many-locals
- from ba.internal import have_pro, get_player_colors
+ from ba.internal import get_player_colors
c_raw = get_player_colors()
- if len(c_raw) != 16:
- raise Exception('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]]
+ uiscale = ba.app.ui.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
@@ -66,14 +48,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)
@@ -112,7 +94,7 @@ class ColorPicker(popup.PopupWindow):
on_activate_call=ba.WeakCall(self._select_other))
# Custom colors are limited to pro currently.
- if not have_pro():
+ if not ba.app.accounts.have_pro():
ba.imagewidget(parent=self.root_widget,
position=(50, 12),
size=(30, 30),
@@ -134,10 +116,9 @@ class ColorPicker(popup.PopupWindow):
def _select_other(self) -> None:
from bastd.ui import purchase
- from ba.internal import have_pro
# Requires pro.
- if not have_pro():
+ if not ba.app.accounts.have_pro():
purchase.PurchaseWindow(items=['pro'])
self._transition_out()
return
@@ -172,7 +153,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,16 +166,16 @@ 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 Exception('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]]
+ uiscale = ba.app.ui.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
@@ -207,15 +188,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,15 +245,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()
- # noinspection PyUnresolvedReferences
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/config.py b/assets/src/ba_data/python/bastd/ui/config.py
index a55c5a95..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
@@ -127,23 +109,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 +134,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 +159,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/configerror.py b/assets/src/ba_data/python/bastd/ui/configerror.py
index 3d6bfc64..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
@@ -47,7 +29,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/confirm.py b/assets/src/ba_data/python/bastd/ui/confirm.py
index 9693b287..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
@@ -68,12 +50,14 @@ class ConfirmWindow:
scale_origin = None
transition = 'in_right'
+ uiscale = ba.app.ui.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,
@@ -145,18 +129,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..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
@@ -94,7 +76,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/__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/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py
index bc5b7d7a..c8d0eee5 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
@@ -29,6 +11,9 @@ from typing import TYPE_CHECKING
import _ba
import ba
+from bastd.ui.store.button import StoreButton
+from bastd.ui.league.rankbutton import LeagueRankButton
+from bastd.ui.store.browser import StoreBrowserWindow
if TYPE_CHECKING:
from typing import Any, Optional, Tuple, Dict, List, Union
@@ -38,29 +23,44 @@ 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.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:
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',
origin_widget: ba.Widget = None):
- # 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
cfg = app.config
+ # 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'),
+ 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:
@@ -73,22 +73,22 @@ 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
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)
- app.main_window = 'Coop Select'
+ 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
+ 730 if uiscale is ba.UIScale.MEDIUM else 800)
+ app.ui.set_main_menu_location('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
@@ -99,20 +99,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.ui.use_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,
@@ -124,11 +123,11 @@ 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 - (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),
@@ -138,8 +137,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,
@@ -184,26 +183,28 @@ 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'),
h_align='center',
- color=app.title_color,
+ color=app.ui.title_color,
scale=1.5,
maxwidth=500,
v_align='center')
- if app.toolbars and app.small_ui:
+ if app.ui.use_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)
@@ -214,8 +215,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.ui.use_toolbars else 160))
self._subcontainerwidth = 800.0
self._subcontainerheight = 1400.0
@@ -223,10 +225,13 @@ 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
- (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)
+ 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.
@@ -246,15 +251,14 @@ class CoopBrowserWindow(ba.Window):
# If we've got a cached tournament list for our account and info for
# each one of those tournaments, go ahead and display it as a
# starting point.
- if (app.account_tournament_list is not None and
- app.account_tournament_list[0] == _ba.get_account_state_num()
- and all([
- t_id in app.tournament_info
- for t_id in app.account_tournament_list[1]
- ])):
+ if (app.accounts.account_tournament_list is not None
+ and app.accounts.account_tournament_list[0]
+ == _ba.get_account_state_num()
+ and all(t_id in app.accounts.tournament_info
+ for t_id in app.accounts.account_tournament_list[1])):
tourney_data = [
- app.tournament_info[t_id]
- for t_id in app.account_tournament_list[1]
+ app.accounts.tournament_info[t_id]
+ for t_id in app.accounts.account_tournament_list[1]
]
self._update_for_data(tourney_data)
@@ -265,7 +269,25 @@ class CoopBrowserWindow(ba.Window):
repeat=True)
self._update()
+ @staticmethod
+ def _preload_modules() -> None:
+ """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
+ 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:
+ # Do nothing if we've somehow outlived our actual UI.
+ if not self._root_widget:
+ return
+
cur_time = ba.time(ba.TimeType.REAL)
# If its been a while since we got a tournament update, consider the
@@ -332,18 +354,18 @@ class CoopBrowserWindow(ba.Window):
self._update_hard_mode_lock_image()
def _update_hard_mode_lock_image(self) -> None:
- from ba.internal import have_pro_options
try:
- ba.imagewidget(edit=self._hard_button_lock_image,
- opacity=0.0 if have_pro_options() else 1.0)
+ ba.imagewidget(
+ edit=self._hard_button_lock_image,
+ opacity=0.0 if ba.app.accounts.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
# 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.
@@ -457,7 +479,8 @@ class CoopBrowserWindow(ba.Window):
tbtn['required_league'] = (None if 'requiredLeague' not in entry
else entry['requiredLeague'])
- game = ba.app.tournament_info[tbtn['tournament_id']]['game']
+ game = ba.app.accounts.tournament_info[
+ tbtn['tournament_id']]['game']
if game is None:
ba.textwidget(edit=tbtn['button_text'], text='-')
@@ -466,20 +489,20 @@ class CoopBrowserWindow(ba.Window):
opacity=0.2)
else:
campaignname, levelname = game.split(':')
- campaign = get_campaign(campaignname)
- max_players = ba.app.tournament_info[
+ campaign = getcampaign(campaignname)
+ max_players = ba.app.accounts.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']
@@ -516,9 +539,9 @@ class CoopBrowserWindow(ba.Window):
ba.charstr(ba.SpecialChar.TICKET_BACKING) +
str(final_fee))
- ad_tries_remaining = ba.app.tournament_info[
+ ad_tries_remaining = ba.app.accounts.tournament_info[
tbtn['tournament_id']]['adTriesRemaining']
- free_tries_remaining = ba.app.tournament_info[
+ free_tries_remaining = ba.app.accounts.tournament_info[
tbtn['tournament_id']]['freeTriesRemaining']
# Now, if this fee allows ads and we support video ads, show
@@ -568,8 +591,7 @@ class CoopBrowserWindow(ba.Window):
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
- from ba.internal import cache_tournament_info
- app = ba.app
+ accounts = ba.app.accounts
if data is not None:
tournament_data = data['t'] # This used to be the whole payload.
self._last_tournament_query_response_time = ba.time(
@@ -580,10 +602,10 @@ class CoopBrowserWindow(ba.Window):
# Keep our cached tourney info up to date.
if data is not None:
self._tourney_data_up_to_date = True
- cache_tournament_info(tournament_data)
+ accounts.cache_tournament_info(tournament_data)
# Also cache the current tourney list/order for this account.
- app.account_tournament_list = (_ba.get_account_state_num(), [
+ accounts.account_tournament_list = (_ba.get_account_state_num(), [
e['tournamentID'] for e in tournament_data
])
@@ -592,10 +614,9 @@ class CoopBrowserWindow(ba.Window):
def _set_campaign_difficulty(self, difficulty: str) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
from bastd.ui.purchase import PurchaseWindow
if difficulty != self._campaign_difficulty:
- if difficulty == 'hard' and not have_pro_options():
+ if difficulty == 'hard' and not ba.app.accounts.have_pro_options():
PurchaseWindow(items=['pro'])
return
ba.playsound(ba.getsound('gunCocking'))
@@ -615,7 +636,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 +737,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.
@@ -733,13 +754,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
@@ -759,17 +780,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:
@@ -781,15 +796,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
@@ -833,7 +848,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,
@@ -867,7 +882,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
@@ -913,7 +928,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 = [
@@ -935,8 +950,8 @@ class CoopBrowserWindow(ba.Window):
# add all custom user levels here..
# items += [
- # 'User:' + l.get_name()
- # for l in get_campaign('User').get_levels()
+ # 'User:' + l.getname()
+ # for l in getcampaign('User').getlevels()
# ]
self._custom_h_scroll = custom_h_scroll = h_scroll = ba.hscrollwidget(
@@ -998,7 +1013,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,
@@ -1329,36 +1344,40 @@ 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')
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:
+ def _switch_to_score(
+ self,
+ show_tab: Optional[
+ StoreBrowserWindow.TabID] = StoreBrowserWindow.TabID.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
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(
- 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
- 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
@@ -1368,7 +1387,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'].
@@ -1376,13 +1395,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())
@@ -1399,9 +1418,8 @@ class CoopBrowserWindow(ba.Window):
# pylint: disable=too-many-statements
# 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] = {}
@@ -1447,23 +1465,23 @@ class CoopBrowserWindow(ba.Window):
return
# Game is whatever the tournament tells us it is.
- game = ba.app.tournament_info[
+ game = ba.app.accounts.tournament_info[
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
# need be.
if tournament_button is None and game in (
'Challenges:Infinite Runaround',
- 'Challenges:Infinite Onslaught') and not have_pro():
+ 'Challenges:Infinite Onslaught'
+ ) and not ba.app.accounts.have_pro():
if _ba.get_account_state() != 'signed_in':
show_sign_in_prompt()
else:
@@ -1500,7 +1518,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:
@@ -1518,16 +1536,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:
- try:
- sel_name = ba.app.window_states[
- self.__class__.__name__]['sel_name']
- except Exception:
- sel_name = None
+ sel_name = ba.app.ui.window_states.get(type(self),
+ {}).get('sel_name')
if sel_name == 'Back':
sel = self._back_button
elif sel_name == 'Scroll':
@@ -1540,7 +1555,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
@@ -1555,12 +1570,10 @@ class CoopBrowserWindow(ba.Window):
elif sel == self._scrollwidget:
sel_name = 'Scroll'
else:
- raise Exception('unrecognized selection')
- ba.app.window_states[self.__class__.__name__] = {
- 'sel_name': sel_name
- }
+ raise ValueError('unrecognized selection')
+ ba.app.ui.window_states[type(self)] = {'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/coop/gamebutton.py b/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py
index f7bd8b87..8aee88b7 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
@@ -40,7 +22,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 getcampaign
self._game = game
sclx = 195.0
scly = 195.0
@@ -54,8 +36,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,11 +77,11 @@ 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
- self._achievements = (get_achievements_for_coop_level(game))
+ translated = campaign.getlevel(levelname).displayname
+ self._achievements = ba.app.ach.achievements_for_coop_level(game)
self._name_widget = ba.textwidget(parent=parent,
draw_controller=btn,
@@ -182,7 +164,12 @@ class GameButton:
def _update(self) -> None:
# pylint: disable=too-many-boolean-expressions
- from ba.internal import have_pro, get_campaign
+ from ba.internal import getcampaign
+
+ # In case we stick around after our UI...
+ if not self._button:
+ return
+
game = self._game
campaignname, levelname = game.split(':')
@@ -192,15 +179,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:
@@ -213,7 +198,8 @@ class GameButton:
# Hard-code games we haven't unlocked.
if ((game in ('Challenges:Infinite Runaround',
- 'Challenges:Infinite Onslaught') and not have_pro())
+ 'Challenges:Infinite Onslaught')
+ and not ba.app.accounts.have_pro())
or (game in ('Challenges:Meteor Shower', )
and not _ba.get_purchased('games.meteor_shower'))
or (game in ('Challenges:Target Practice',
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..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
@@ -32,10 +14,12 @@ class CoopLevelLockedWindow(ba.Window):
width = 550.0
height = 250.0
lock_tex = ba.gettexture('lock')
+ uiscale = ba.app.ui.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),
@@ -54,7 +38,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 a69aa613..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
@@ -51,9 +33,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.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
self._r = 'creditsWindow'
super().__init__(root_widget=ba.containerwidget(
@@ -61,39 +44,43 @@ 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.ui.use_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}',
ba.Lstr(resource='titleText'))]),
h_align='center',
- color=ba.app.title_color,
+ color=ba.app.ui.title_color,
maxwidth=330,
v_align='center')
@@ -103,10 +90,10 @@ 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 ba.app.small_ui:
+ if uiscale is ba.UIScale.SMALL:
ba.widget(edit=scroll,
left_widget=_ba.get_special_widget('back_button'))
@@ -173,7 +160,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)
@@ -275,8 +262,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 50b8c670..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
@@ -38,9 +20,10 @@ class DebugWindow(ba.Window):
# pylint: disable=cyclic-import
from bastd.ui import popup
+ uiscale = ba.app.ui.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 +37,13 @@ class DebugWindow(ba.Window):
self._stress_test_round_duration = 30
self._r = 'debugWindow'
+ uiscale = ba.app.ui.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,
@@ -75,7 +59,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)
@@ -128,7 +112,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')
@@ -141,7 +125,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')
@@ -167,7 +151,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')
@@ -331,5 +315,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 b762abd0..7d4db7c2 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
@@ -35,16 +17,22 @@ def ask_for_rating() -> Optional[ba.Widget]:
app = ba.app
platform = app.platform
subplatform = app.subplatform
+
+ # FIXME: should whitelist platforms we *do* want this for.
+ if ba.app.test_build:
+ return None
if not (platform == 'mac' or (platform == 'android'
and subplatform in ['google', 'cardboard'])):
return None
width = 700
height = 400
spacing = 40
+ uiscale = ba.app.ui.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
@@ -55,7 +43,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'))]),
@@ -66,11 +54,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/fileselector.py b/assets/src/ba_data/python/bastd/ui/fileselector.py
index 27c34818..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
@@ -45,9 +27,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.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
self._callback = callback
self._base_path = path
self._path: Optional[str] = None
@@ -65,13 +48,14 @@ 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),
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
@@ -119,7 +103,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,
@@ -181,7 +165,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
deleted file mode 100644
index 1ba440bc..00000000
--- a/assets/src/ba_data/python/bastd/ui/gather.py
+++ /dev/null
@@ -1,1997 +0,0 @@
-# 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.
-# -----------------------------------------------------------------------------
-"""Provides UI for inviting/joining friends."""
-# pylint: disable=too-many-lines
-
-from __future__ import annotations
-
-import threading
-import time
-from typing import TYPE_CHECKING, cast
-
-import _ba
-import ba
-
-if TYPE_CHECKING:
- from typing import Any, Optional, Tuple, Dict, List, Union, Callable
-
-
-class GatherWindow(ba.Window):
- """Window for joining/inviting friends."""
-
- def __del__(self) -> None:
- _ba.set_party_icon_always_visible(False)
-
- def __init__(self,
- transition: Optional[str] = 'in_right',
- origin_widget: ba.Widget = None):
- # pylint: disable=too-many-statements
- # pylint: disable=too-many-locals
- from bastd.ui import tabs
- ba.set_analytics_screen('Gather Window')
- 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
- 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)
- self._current_tab: Optional[str] = None
- extra_top = 20 if ba.app.small_ui else 0
- self._r = 'gatherWindow'
- self._tab_data: Any = None
- self._internet_local_address: Optional[str] = None
- self._internet_host_text: Optional[ba.Widget] = None
- self._internet_join_text: Optional[ba.Widget] = None
- self._doing_access_check: Optional[bool] = None
- self._access_check_count: Optional[int] = None
- self._public_party_list_selection: Optional[Tuple[str, str]] = None
- self._internet_tab: Optional[str] = None
- self._internet_join_last_refresh_time = -99999.0
- self._last_public_party_list_rebuild_time: Optional[float] = None
- self._first_public_party_list_rebuild_time: Optional[float] = None
- self._internet_join_party_name_label: Optional[ba.Widget] = None
- self._internet_join_party_language_label: Optional[ba.Widget] = None
- self._internet_join_party_size_label: Optional[ba.Widget] = None
- self._internet_join_party_ping_label: Optional[ba.Widget] = None
- self._internet_host_scrollwidget: Optional[ba.Widget] = None
- self._internet_host_columnwidget: Optional[ba.Widget] = None
- self._internet_join_status_text: Optional[ba.Widget] = None
- self._internet_host_name_label_text: Optional[ba.Widget] = None
- self._internet_host_name_text: Optional[ba.Widget] = None
- self._internet_host_max_party_size_label: Optional[ba.Widget] = None
- self._internet_host_max_party_size_value: Optional[ba.Widget] = None
- self._internet_host_max_party_size_minus_button: (
- Optional[ba.Widget]) = None
- self._internet_host_max_party_size_plus_button: (
- Optional[ba.Widget]) = None
- self._internet_host_toggle_button: Optional[ba.Widget] = None
- self._internet_host_status_text: Optional[ba.Widget] = None
- self._internet_host_dedicated_server_info_text: (
- Optional[ba.Widget]) = None
- self._internet_lock_icon: Optional[ba.Widget] = None
- self._next_public_party_entry_index = 0
- self._refreshing_public_party_list: Optional[bool] = None
- self._last_public_party_connect_attempt_time: Optional[float] = None
- self._t_addr: Optional[ba.Widget] = None
- self._t_accessible: Optional[ba.Widget] = None
- self._t_accessible_extra: Optional[ba.Widget] = None
-
- 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, -11) if ba.app.small_ui else (
- 0, 0) if ba.app.med_ui else (0, 0)))
-
- if ba.app.small_ui and ba.app.toolbars:
- ba.containerwidget(edit=self._root_widget,
- on_cancel_call=self._back)
- self._back_button = None
- else:
- self._back_button = btn = ba.buttonwidget(
- parent=self._root_widget,
- position=(70 + x_offs, self._height - 74),
- size=(140, 60),
- scale=1.1,
- autoselect=True,
- label=ba.Lstr(resource='backText'),
- button_type='back',
- on_activate_call=self._back)
- ba.containerwidget(edit=self._root_widget, cancel_button=btn)
- ba.buttonwidget(edit=btn,
- button_type='backSmall',
- position=(70 + x_offs, self._height - 78),
- size=(60, 60),
- label=ba.charstr(ba.SpecialChar.BACK))
-
- ba.textwidget(parent=self._root_widget,
- position=(self._width * 0.5, self._height - 42),
- size=(0, 0),
- color=ba.app.title_color,
- scale=1.5,
- h_align='center',
- v_align='center',
- text=ba.Lstr(resource=self._r + '.titleText'),
- maxwidth=550)
-
- platform = ba.app.platform
- subplatform = ba.app.subplatform
-
- tabs_def: List[Tuple[str, ba.Lstr]] = [
- ('about', ba.Lstr(resource=self._r + '.aboutText'))
- ]
- if _ba.get_account_misc_read_val('enablePublicParties', True):
- tabs_def.append(
- ('internet', ba.Lstr(resource=self._r + '.internetText')))
- if platform == 'android' and subplatform == 'google':
- tabs_def.append(
- ('google_play', ba.Lstr(resource=self._r + '.googlePlayText')))
- tabs_def.append(
- ('local_network', ba.Lstr(resource=self._r + '.localNetworkText')))
-
- tabs_def.append(('manual', ba.Lstr(resource=self._r + '.manualText')))
-
- scroll_buffer_h = 130 + 2 * x_offs
- tab_buffer_h = 250 + 2 * x_offs
-
- self._tab_buttons = tabs.create_tab_buttons(
- self._root_widget,
- tabs_def,
- pos=(tab_buffer_h * 0.5, self._height - 130),
- size=(self._width - tab_buffer_h, 50),
- on_select_call=self._set_tab)
-
- 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:
- ba.widget(edit=self._tab_buttons[tabs_def[0][0]],
- left_widget=_ba.get_special_widget('back_button'))
-
- self._scroll_width = self._width - scroll_buffer_h
- self._scroll_height = self._height - 180.0
-
- # Not actually using a scroll widget anymore; just an image.
- scroll_left = (self._width - self._scroll_width) * 0.5
- scroll_bottom = self._height - self._scroll_height - 79 - 48
- buffer_h = 10
- buffer_v = 4
- ba.imagewidget(parent=self._root_widget,
- position=(scroll_left - buffer_h,
- scroll_bottom - buffer_v),
- size=(self._scroll_width + 2 * buffer_h,
- self._scroll_height + 2 * buffer_v),
- texture=ba.gettexture('scrollWidget'),
- model_transparent=ba.getmodel('softEdgeOutside'))
- self._tab_container: Optional[ba.Widget] = None
- self._restore_state()
-
- def get_r(self) -> str:
- """(internal)"""
- return self._r
-
- def _on_google_play_show_invites_press(self) -> None:
- from bastd.ui import account
- if (_ba.get_account_state() != 'signed_in'
- or _ba.get_account_type() != 'Google Play'):
- account.show_sign_in_prompt('Google Play')
- else:
- _ba.show_invites_ui()
-
- def _on_google_play_invite_press(self) -> None:
- from bastd.ui import confirm
- from bastd.ui import account
- if (_ba.get_account_state() != 'signed_in'
- or _ba.get_account_type() != 'Google Play'):
- account.show_sign_in_prompt('Google Play')
- else:
- # If there's google play people connected to us, inform the user
- # that they will get disconnected. Otherwise just go ahead.
- google_player_count = (_ba.get_google_play_party_client_count())
- if google_player_count > 0:
- confirm.ConfirmWindow(
- ba.Lstr(resource=self._r + '.googlePlayReInviteText',
- subs=[('${COUNT}', str(google_player_count))]),
- lambda: ba.timer(
- 0.2, _ba.invite_players, timetype=ba.TimeType.REAL),
- width=500,
- height=150,
- ok_text=ba.Lstr(resource=self._r +
- '.googlePlayInviteText'))
- else:
- ba.timer(0.1, _ba.invite_players, timetype=ba.TimeType.REAL)
-
- def _invite_to_try_press(self) -> None:
- from bastd.ui import account
- from bastd.ui import appinvite
- if _ba.get_account_state() != 'signed_in':
- account.show_sign_in_prompt()
- return
- appinvite.handle_app_invites_press()
-
- def _set_tab(self, tab: str) -> None:
- # pylint: disable=too-many-statements
- # pylint: disable=too-many-locals
- from bastd.ui import tabs
- if self._current_tab == tab:
- return
- self._current_tab = tab
-
- # We wanna preserve our current tab between runs.
- cfg = ba.app.config
- cfg['Gather Tab'] = tab
- cfg.commit()
-
- # Update tab colors based on which is selected.
- tabs.update_tab_button_colors(self._tab_buttons, tab)
-
- # (Re)create scroll widget.
- if self._tab_container:
- self._tab_container.delete()
- scroll_left = (self._width - self._scroll_width) * 0.5
- scroll_bottom = self._height - self._scroll_height - 79 - 48
-
- # A place where tabs can store data to get cleared when switching to
- # a different tab.
- self._tab_data = {}
-
- # So we can still select root level widgets with direction buttons.
- def _simple_message(tab2: str,
- message: ba.Lstr,
- string_height: float,
- include_invite: bool = False) -> None:
- msc_scale = 1.1
- c_width_2 = self._scroll_width
- c_height_2 = min(self._scroll_height,
- string_height * msc_scale + 100)
- try_tickets = _ba.get_account_misc_read_val(
- 'friendTryTickets', None)
- if try_tickets is None:
- include_invite = False
- self._tab_container = cnt2 = ba.containerwidget(
- parent=self._root_widget,
- position=(scroll_left, scroll_bottom +
- (self._scroll_height - c_height_2) * 0.5),
- size=(c_width_2, c_height_2),
- background=False,
- selectable=include_invite)
- ba.widget(edit=cnt2, up_widget=self._tab_buttons[tab2])
-
- ba.textwidget(
- parent=cnt2,
- position=(c_width_2 * 0.5,
- c_height_2 * (0.58 if include_invite else 0.5)),
- color=(0.6, 1.0, 0.6),
- scale=msc_scale,
- size=(0, 0),
- maxwidth=c_width_2 * 0.9,
- max_height=c_height_2 * (0.7 if include_invite else 0.9),
- h_align='center',
- v_align='center',
- text=message)
- if include_invite:
- ba.textwidget(parent=cnt2,
- position=(c_width_2 * 0.57, 35),
- color=(0, 1, 0),
- scale=0.6,
- size=(0, 0),
- maxwidth=c_width_2 * 0.5,
- h_align='right',
- v_align='center',
- flatness=1.0,
- text=ba.Lstr(
- resource=self._r + '.inviteAFriendText',
- subs=[('${COUNT}', str(try_tickets))]))
- ba.buttonwidget(
- parent=cnt2,
- position=(c_width_2 * 0.59, 10),
- size=(230, 50),
- color=(0.54, 0.42, 0.56),
- textcolor=(0, 1, 0),
- label=ba.Lstr(resource='gatherWindow.inviteFriendsText',
- fallback_resource=(
- 'gatherWindow.getFriendInviteCodeText')),
- autoselect=True,
- on_activate_call=ba.WeakCall(self._invite_to_try_press),
- up_widget=self._tab_buttons[tab2])
-
- if tab == 'about':
- msg = ba.Lstr(resource=self._r + '.aboutDescriptionText',
- subs=[('${PARTY}',
- ba.charstr(ba.SpecialChar.PARTY_ICON)),
- ('${BUTTON}',
- ba.charstr(ba.SpecialChar.TOP_BUTTON))])
-
- # Let's not talk about sharing in vr-mode; its tricky to fit more
- # than one head in a VR-headset ;-)
- if not ba.app.vr_mode:
- msg = ba.Lstr(
- value='${A}\n\n${B}',
- subs=[
- ('${A}', msg),
- ('${B}',
- ba.Lstr(resource=self._r +
- '.aboutDescriptionLocalMultiplayerExtraText'))
- ])
-
- _simple_message(tab, msg, 400, include_invite=True)
-
- 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 +
- (self._scroll_height - c_height) * 0.5),
- 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(
- 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),
- )
-
- elif tab == 'internet':
- c_width = self._scroll_width
- c_height = self._scroll_height - 20
- self._tab_container = cnt = ba.containerwidget(
- parent=self._root_widget,
- position=(scroll_left, scroll_bottom +
- (self._scroll_height - c_height) * 0.5),
- size=(c_width, c_height),
- background=False,
- selection_loop_to_parent=True)
- v = c_height - 30
- self._internet_join_text = txt = ba.textwidget(
- parent=cnt,
- position=(c_width * 0.5 - 245, v - 13),
- color=(0.6, 1.0, 0.6),
- scale=1.3,
- size=(200, 30),
- maxwidth=250,
- h_align='left',
- v_align='center',
- click_activate=True,
- selectable=True,
- autoselect=True,
- on_activate_call=lambda: self._set_internet_tab(
- 'join', playsound=True),
- text=ba.Lstr(resource=self._r +
- '.joinPublicPartyDescriptionText'))
- ba.widget(edit=txt, up_widget=self._tab_buttons[tab])
- self._internet_host_text = txt = ba.textwidget(
- parent=cnt,
- position=(c_width * 0.5 + 45, v - 13),
- color=(0.6, 1.0, 0.6),
- scale=1.3,
- size=(200, 30),
- maxwidth=250,
- h_align='left',
- v_align='center',
- click_activate=True,
- selectable=True,
- autoselect=True,
- on_activate_call=lambda: self._set_internet_tab(
- 'host', playsound=True),
- text=ba.Lstr(resource=self._r +
- '.hostPublicPartyDescriptionText'))
- ba.widget(edit=txt,
- left_widget=self._internet_join_text,
- up_widget=self._tab_buttons[tab])
- ba.widget(edit=self._internet_join_text, right_widget=txt)
-
- # Attempt to fetch our local address so we have it for
- # error messages.
- self._internet_local_address = None
-
- class AddrFetchThread(threading.Thread):
- """Thread for fetching an address in the bg."""
-
- def __init__(self, call: Callable[[Any], Any]):
- super().__init__()
- self._call = call
-
- def run(self) -> None:
- try:
- # FIXME: Update this to work with IPv6 at some point.
- import socket
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- 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()
-
- AddrFetchThread(ba.WeakCall(
- self._internet_fetch_local_addr_cb)).start()
-
- assert self._internet_tab is not None
- self._set_internet_tab(self._internet_tab)
- self._tab_data = {
- 'update_timer':
- ba.Timer(0.2,
- ba.WeakCall(self._update_internet_tab),
- repeat=True,
- timetype=ba.TimeType.REAL)
- }
-
- # Also update it immediately so we don't have to wait for the
- # initial query.
- self._update_internet_tab()
-
- elif tab == 'local_network':
- c_width = self._scroll_width
- c_height = self._scroll_height - 20
- sub_scroll_height = c_height - 85
- sub_scroll_width = 650
-
- class NetScanner:
- """Class for scanning for games on the lan."""
-
- def __init__(self, scrollwidget: ba.Widget,
- tab_button: ba.Widget, width: float):
- self._scrollwidget = scrollwidget
- self._tab_button = tab_button
- self._columnwidget = ba.columnwidget(
- parent=self._scrollwidget, left_border=10)
- ba.widget(edit=self._columnwidget, up_widget=tab_button)
- self._width = width
- self._last_selected_host: Optional[Dict[str, Any]] = None
-
- self._update_timer = ba.Timer(1.0,
- ba.WeakCall(self.update),
- timetype=ba.TimeType.REAL,
- repeat=True)
- # Go ahead and run a few *almost* immediately so we don't
- # have to wait a second.
- self.update()
- ba.timer(0.25,
- ba.WeakCall(self.update),
- timetype=ba.TimeType.REAL)
-
- def __del__(self) -> None:
- _ba.end_host_scanning()
-
- def _on_select(self, host: Dict[str, Any]) -> None:
- self._last_selected_host = host
-
- def _on_activate(self, host: Dict[str, Any]) -> None:
- _ba.connect_to_party(host['address'])
-
- def update(self) -> None:
- """(internal)"""
- t_scale = 1.6
- for child in self._columnwidget.get_children():
- child.delete()
-
- # Grab this now this since adding widgets will change it.
- last_selected_host = self._last_selected_host
- hosts = _ba.host_scan_cycle()
- for i, host in enumerate(hosts):
- txt3 = ba.textwidget(
- parent=self._columnwidget,
- size=(self._width / t_scale, 30),
- selectable=True,
- color=(1, 1, 1),
- on_select_call=ba.Call(self._on_select, host),
- on_activate_call=ba.Call(self._on_activate, host),
- click_activate=True,
- text=host['display_string'],
- h_align='left',
- v_align='center',
- corner_scale=t_scale,
- maxwidth=(self._width / t_scale) * 0.93)
- if host == last_selected_host:
- ba.containerwidget(edit=self._columnwidget,
- selected_child=txt3,
- visible_child=txt3)
- if i == 0:
- ba.widget(edit=txt3, up_widget=self._tab_button)
-
- self._tab_container = cnt = ba.containerwidget(
- parent=self._root_widget,
- position=(scroll_left, scroll_bottom +
- (self._scroll_height - c_height) * 0.5),
- size=(c_width, c_height),
- background=False,
- selection_loop_to_parent=True)
- v = c_height - 30
- ba.textwidget(parent=cnt,
- position=(c_width * 0.5, v - 3),
- 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 +
- '.localNetworkDescriptionText'))
- v -= 15
- v -= sub_scroll_height + 23
- scrollw = ba.scrollwidget(
- parent=cnt,
- position=((self._scroll_width - sub_scroll_width) * 0.5, v),
- size=(sub_scroll_width, sub_scroll_height))
-
- self._tab_data = NetScanner(scrollw,
- self._tab_buttons[tab],
- width=sub_scroll_width)
-
- ba.widget(edit=scrollw,
- autoselect=True,
- up_widget=self._tab_buttons[tab])
-
- elif tab == 'bluetooth':
- c_width = self._scroll_width
- c_height = 380
- sub_scroll_width = 650
-
- self._tab_container = cnt = ba.containerwidget(
- parent=self._root_widget,
- position=(scroll_left, scroll_bottom +
- (self._scroll_height - c_height) * 0.5),
- size=(c_width, c_height),
- background=False,
- selection_loop_to_parent=True)
- 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 +
- '.bluetoothDescriptionText'))
- 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 +
- '.bluetoothAndroidSupportText'))
-
- v -= 55
- btn = ba.buttonwidget(
- parent=cnt,
- position=(c_width * 0.5 - sub_scroll_width * 0.5 + 10, v - 75),
- size=(300, 70),
- autoselect=True,
- label=ba.Lstr(resource=self._r + '.bluetoothHostText'))
- ba.widget(edit=btn, up_widget=self._tab_buttons[tab])
- btn = ba.buttonwidget(
- parent=cnt,
- position=(c_width * 0.5 - sub_scroll_width * 0.5 + 330,
- v - 75),
- size=(300, 70),
- autoselect=True,
- on_activate_call=ba.Call(ba.screenmessage,
- 'FIXME: Not wired up yet.'),
- label=ba.Lstr(resource=self._r + '.bluetoothJoinText'))
- ba.widget(edit=btn, up_widget=self._tab_buttons[tab])
- ba.widget(edit=self._tab_buttons[tab], down_widget=btn)
-
- elif tab == 'wifi_direct':
- c_width = self._scroll_width
- c_height = self._scroll_height - 20
- self._tab_container = cnt = ba.containerwidget(
- parent=self._root_widget,
- position=(scroll_left, scroll_bottom +
- (self._scroll_height - c_height) * 0.5),
- size=(c_width, c_height),
- background=False,
- selection_loop_to_parent=True)
- v = c_height - 80
-
- ba.textwidget(parent=cnt,
- position=(c_width * 0.5, v),
- color=(0.6, 1.0, 0.6),
- scale=1.0,
- size=(0, 0),
- maxwidth=c_width * 0.95,
- max_height=140,
- h_align='center',
- v_align='center',
- text=ba.Lstr(resource=self._r +
- '.wifiDirectDescriptionTopText'))
- v -= 140
- btn = ba.buttonwidget(
- parent=cnt,
- position=(c_width * 0.5 - 175, v),
- size=(350, 65),
- label=ba.Lstr(resource=self._r +
- '.wifiDirectOpenWiFiSettingsText'),
- autoselect=True,
- on_activate_call=_ba.android_show_wifi_settings)
- v -= 82
-
- ba.widget(edit=btn, up_widget=self._tab_buttons[tab])
-
- ba.textwidget(parent=cnt,
- position=(c_width * 0.5, v),
- color=(0.6, 1.0, 0.6),
- scale=0.9,
- size=(0, 0),
- maxwidth=c_width * 0.95,
- max_height=150,
- h_align='center',
- v_align='center',
- text=ba.Lstr(resource=self._r +
- '.wifiDirectDescriptionBottomText',
- subs=[('${APP_NAME}',
- ba.Lstr(resource='titleText'))]))
-
- elif tab == 'manual':
- c_width = self._scroll_width
- c_height = 380
- last_addr = ba.app.config.get('Last Manual Party Connect Address',
- '')
-
- self._tab_container = cnt = ba.containerwidget(
- parent=self._root_widget,
- position=(scroll_left, scroll_bottom +
- (self._scroll_height - c_height) * 0.5),
- size=(c_width, c_height),
- background=False,
- selection_loop_to_parent=True)
- 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 +
- '.manualDescriptionText'))
- v -= 30
- v -= 70
- ba.textwidget(parent=cnt,
- position=(c_width * 0.5 - 260 - 50, v),
- color=(0.6, 1.0, 0.6),
- scale=1.0,
- size=(0, 0),
- maxwidth=130,
- h_align='right',
- v_align='center',
- text=ba.Lstr(resource=self._r +
- '.manualAddressText'))
- txt = ba.textwidget(parent=cnt,
- editable=True,
- description=ba.Lstr(resource=self._r +
- '.manualAddressText'),
- position=(c_width * 0.5 - 240 - 50, v - 30),
- text=last_addr,
- autoselect=True,
- v_align='center',
- scale=1.0,
- size=(420, 60))
- ba.textwidget(parent=cnt,
- position=(c_width * 0.5 - 260 + 490, v),
- color=(0.6, 1.0, 0.6),
- scale=1.0,
- size=(0, 0),
- maxwidth=80,
- h_align='right',
- v_align='center',
- text=ba.Lstr(resource=self._r + '.portText'))
- txt2 = ba.textwidget(parent=cnt,
- editable=True,
- description=ba.Lstr(resource=self._r +
- '.portText'),
- text='43210',
- autoselect=True,
- max_chars=5,
- position=(c_width * 0.5 - 240 + 490, v - 30),
- v_align='center',
- scale=1.0,
- size=(170, 60))
-
- v -= 110
-
- def _connect(textwidget: ba.Widget,
- port_textwidget: ba.Widget) -> None:
- addr = cast(str, ba.textwidget(query=textwidget))
- if addr == '':
- ba.screenmessage(
- ba.Lstr(resource='internal.invalidAddressErrorText'),
- color=(1, 0, 0))
- ba.playsound(ba.getsound('error'))
- return
- try:
- port = int(cast(str, ba.textwidget(query=port_textwidget)))
- if port > 65535 or port < 0:
- raise Exception()
- except Exception:
- ba.screenmessage(
- ba.Lstr(resource='internal.invalidPortErrorText'),
- color=(1, 0, 0))
- ba.playsound(ba.getsound('error'))
- return
-
- class HostAddrFetchThread(threading.Thread):
- """Thread to fetch an addr."""
-
- def __init__(self, name: str,
- call: Callable[[Optional[str]], Any]):
- super().__init__()
- self._name = name
- self._call = call
-
- def run(self) -> None:
- try:
- import socket
- addr2 = socket.gethostbyname(self._name)
- ba.pushcall(ba.Call(self._call, addr2),
- from_other_thread=True)
- except Exception:
- ba.pushcall(ba.Call(self._call, None),
- from_other_thread=True)
-
- def do_it_2(addr2: Optional[str]) -> None:
- if addr2 is None:
- ba.screenmessage(ba.Lstr(
- resource='internal.unableToResolveHostText'),
- color=(1, 0, 0))
- ba.playsound(ba.getsound('error'))
- else:
- # Store for later.
- cfg2 = ba.app.config
- cfg2['Last Manual Party Connect Address'] = addr2
- cfg2.commit()
- _ba.connect_to_party(addr2, port=port)
-
- HostAddrFetchThread(addr, do_it_2).start()
-
- btn = ba.buttonwidget(
- parent=cnt,
- size=(300, 70),
- label=ba.Lstr(resource=self._r + '.manualConnectText'),
- position=(c_width * 0.5 - 150, v),
- autoselect=True,
- on_activate_call=ba.Call(_connect, txt, txt2))
- ba.widget(edit=txt, up_widget=self._tab_buttons[tab])
- ba.textwidget(edit=txt, on_return_press_call=btn.activate)
- ba.textwidget(edit=txt2, on_return_press_call=btn.activate)
- v -= 45
-
- tscl = 0.85
- tspc = 25
-
- def _safe_set_text(txt3: ba.Widget,
- val: Union[str, ba.Lstr],
- success: bool = True) -> None:
- if txt3:
- ba.textwidget(edit=txt3,
- text=val,
- color=(0, 1, 0) if success else (1, 1, 0))
-
- # This currently doesn't work from china since we go through a
- # reverse proxy there.
- # UPDATE: it should work now; our proxy server forwards along
- # original IPs.
- do_internet_check = True
-
- def do_it(v2: float, cnt2: Optional[ba.Widget]) -> None:
- if not cnt2:
- return
-
- ba.playsound(ba.getsound('swish'))
- ba.textwidget(parent=cnt2,
- position=(c_width * 0.5 - 10, v2),
- color=(0.6, 1.0, 0.6),
- scale=tscl,
- size=(0, 0),
- maxwidth=c_width * 0.45,
- flatness=1.0,
- h_align='right',
- v_align='center',
- text=ba.Lstr(resource=self._r +
- '.manualYourLocalAddressText'))
- txt3 = ba.textwidget(parent=cnt2,
- position=(c_width * 0.5, v2),
- color=(0.5, 0.5, 0.5),
- scale=tscl,
- size=(0, 0),
- maxwidth=c_width * 0.45,
- flatness=1.0,
- h_align='left',
- v_align='center',
- text=ba.Lstr(resource=self._r +
- '.checkingText'))
-
- class AddrFetchThread2(threading.Thread):
- """Thread for fetching an addr."""
-
- def __init__(self, window: GatherWindow,
- textwidget: ba.Widget):
- super().__init__()
- self._window = window
- self._textwidget = textwidget
-
- def run(self) -> None:
- try:
- # FIXME: Update this to work with IPv6.
- import socket
- sock = socket.socket(socket.AF_INET,
- socket.SOCK_DGRAM)
- 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(_safe_set_text,
- self._textwidget, val),
- from_other_thread=True)
- except Exception as exc:
- err_str = str(exc)
-
- # FIXME: Should look at exception types here,
- # not strings.
- if 'Network is unreachable' in err_str:
- ba.pushcall(ba.Call(
- _safe_set_text, self._textwidget,
- ba.Lstr(resource=self._window.get_r() +
- '.noConnectionText'), False),
- from_other_thread=True)
- else:
- ba.pushcall(ba.Call(
- _safe_set_text, self._textwidget,
- ba.Lstr(resource=self._window.get_r() +
- '.addressFetchErrorText'), False),
- from_other_thread=True)
- ba.pushcall(ba.Call(
- ba.print_error,
- 'error in AddrFetchThread: ' + str(exc)),
- from_other_thread=True)
-
- AddrFetchThread2(self, txt3).start()
-
- v2 -= tspc
- ba.textwidget(
- parent=cnt2,
- position=(c_width * 0.5 - 10, v2),
- color=(0.6, 1.0, 0.6),
- scale=tscl,
- size=(0, 0),
- maxwidth=c_width * 0.45,
- flatness=1.0,
- h_align='right',
- v_align='center',
- text=ba.Lstr(resource=self._r +
- '.manualYourAddressFromInternetText'))
-
- t_addr = ba.textwidget(parent=cnt2,
- position=(c_width * 0.5, v2),
- color=(0.5, 0.5, 0.5),
- scale=tscl,
- size=(0, 0),
- maxwidth=c_width * 0.45,
- h_align='left',
- v_align='center',
- flatness=1.0,
- text=ba.Lstr(resource=self._r +
- '.checkingText'))
- v2 -= tspc
- ba.textwidget(parent=cnt2,
- position=(c_width * 0.5 - 10, v2),
- color=(0.6, 1.0, 0.6),
- scale=tscl,
- size=(0, 0),
- maxwidth=c_width * 0.45,
- flatness=1.0,
- h_align='right',
- v_align='center',
- text=ba.Lstr(resource=self._r +
- '.manualJoinableFromInternetText'))
-
- t_accessible = ba.textwidget(parent=cnt2,
- position=(c_width * 0.5, v2),
- color=(0.5, 0.5, 0.5),
- scale=tscl,
- size=(0, 0),
- maxwidth=c_width * 0.45,
- flatness=1.0,
- h_align='left',
- v_align='center',
- text=ba.Lstr(resource=self._r +
- '.checkingText'))
- v2 -= 28
- t_accessible_extra = ba.textwidget(parent=cnt2,
- position=(c_width * 0.5,
- v2),
- color=(1, 0.5, 0.2),
- scale=0.7,
- size=(0, 0),
- maxwidth=c_width * 0.9,
- flatness=1.0,
- h_align='center',
- v_align='center',
- text='')
-
- self._doing_access_check = False
- self._access_check_count = 0 # Cap our refreshes eventually.
- self._tab_data['access_check_timer'] = ba.Timer(
- 10.0,
- ba.WeakCall(self._access_check_update, t_addr,
- t_accessible, t_accessible_extra),
- repeat=True,
- timetype=ba.TimeType.REAL)
-
- # Kick initial off.
- self._access_check_update(t_addr, t_accessible,
- t_accessible_extra)
- if check_button:
- check_button.delete()
-
- if do_internet_check:
- check_button = ba.textwidget(
- parent=cnt,
- size=(250, 60),
- text=ba.Lstr(resource=self._r + '.showMyAddressText'),
- v_align='center',
- h_align='center',
- click_activate=True,
- position=(c_width * 0.5 - 125, v - 30),
- autoselect=True,
- color=(0.5, 0.9, 0.5),
- scale=0.8,
- selectable=True,
- on_activate_call=ba.Call(do_it, v, cnt))
-
- def _internet_fetch_local_addr_cb(self, val: str) -> None:
- self._internet_local_address = str(val)
-
- def _set_internet_tab(self, value: str, playsound: bool = False) -> None:
- # pylint: disable=too-many-locals
- # pylint: disable=too-many-statements
- if playsound:
- ba.playsound(ba.getsound('click01'))
-
- # If we're switching in from elsewhere, reset our selection.
- # (prevents selecting something way down the list if we switched away
- # and came back)
- if self._internet_tab != value:
- self._public_party_list_selection = None
-
- self._internet_tab = value
- active_color = (0.6, 1.0, 0.6)
- inactive_color = (0.5, 0.4, 0.5)
- ba.textwidget(
- edit=self._internet_join_text,
- color=active_color if value == 'join' else inactive_color)
- ba.textwidget(
- edit=self._internet_host_text,
- color=active_color if value == 'host' else inactive_color)
-
- # Clear anything in existence.
- for widget in [
- self._internet_host_scrollwidget,
- self._internet_host_name_text,
- self._internet_host_toggle_button,
- self._internet_host_name_label_text,
- self._internet_host_status_text,
- self._internet_join_party_size_label,
- self._internet_join_party_name_label,
- self._internet_join_party_language_label,
- self._internet_join_party_ping_label,
- self._internet_host_max_party_size_label,
- self._internet_host_max_party_size_value,
- self._internet_host_max_party_size_minus_button,
- self._internet_host_max_party_size_plus_button,
- self._internet_join_status_text,
- self._internet_host_dedicated_server_info_text
- ]:
- if widget is not None:
- widget.delete()
-
- c_width = self._scroll_width
- c_height = self._scroll_height - 20
- sub_scroll_height = c_height - 90
- sub_scroll_width = 830
- v = c_height - 35
- v -= 25
- is_public_enabled = _ba.get_public_party_enabled()
- if value == 'join':
- # Reset this so we do an immediate refresh query.
- self._internet_join_last_refresh_time = -99999.0
-
- # Reset our list of public parties.
- self._public_parties = {}
- self._last_public_party_list_rebuild_time = 0
- self._first_public_party_list_rebuild_time = None
- self._internet_join_party_name_label = ba.textwidget(
- text=ba.Lstr(resource='nameText'),
- parent=self._tab_container,
- size=(0, 0),
- position=(90, v - 8),
- maxwidth=60,
- scale=0.6,
- color=(0.5, 0.5, 0.5),
- flatness=1.0,
- shadow=0.0,
- h_align='center',
- v_align='center')
- if bool(False):
- self._internet_join_party_language_label = ba.textwidget(
- text=ba.Lstr(
- resource='settingsWindowAdvanced.languageText'),
- parent=self._tab_container,
- size=(0, 0),
- position=(662, v - 8),
- maxwidth=100,
- scale=0.6,
- color=(0.5, 0.5, 0.5),
- flatness=1.0,
- shadow=0.0,
- h_align='center',
- v_align='center')
- self._internet_join_party_size_label = ba.textwidget(
- text=ba.Lstr(resource=self._r + '.partySizeText'),
- parent=self._tab_container,
- size=(0, 0),
- position=(755, v - 8),
- maxwidth=60,
- scale=0.6,
- color=(0.5, 0.5, 0.5),
- flatness=1.0,
- shadow=0.0,
- h_align='center',
- v_align='center')
- self._internet_join_party_ping_label = ba.textwidget(
- text=ba.Lstr(resource=self._r + '.pingText'),
- parent=self._tab_container,
- size=(0, 0),
- position=(825, v - 8),
- maxwidth=60,
- scale=0.6,
- color=(0.5, 0.5, 0.5),
- flatness=1.0,
- shadow=0.0,
- h_align='center',
- v_align='center')
- v -= sub_scroll_height + 23
-
- self._internet_host_scrollwidget = scrollw = ba.scrollwidget(
- parent=self._tab_container,
- simple_culling_v=10,
- position=((self._scroll_width - sub_scroll_width) * 0.5, v),
- size=(sub_scroll_width, sub_scroll_height))
- ba.widget(edit=scrollw, autoselect=True)
- colw = self._internet_host_columnwidget = ba.containerwidget(
- parent=scrollw, background=False, size=(400, 400))
- ba.containerwidget(edit=scrollw, claims_left_right=True)
- ba.containerwidget(edit=colw, claims_left_right=True)
-
- self._internet_join_status_text = ba.textwidget(
- parent=self._tab_container,
- text=ba.Lstr(value='${A}...',
- subs=[('${A}',
- ba.Lstr(resource='store.loadingText'))]),
- size=(0, 0),
- scale=0.9,
- flatness=1.0,
- shadow=0.0,
- h_align='center',
- v_align='top',
- maxwidth=c_width,
- color=(0.6, 0.6, 0.6),
- position=(c_width * 0.5, c_height * 0.5))
-
- if value == 'host':
- v -= 30
- party_name_text = ba.Lstr(
- resource='gatherWindow.partyNameText',
- fallback_resource='editGameListWindow.nameText')
- self._internet_host_name_label_text = ba.textwidget(
- parent=self._tab_container,
- size=(0, 0),
- h_align='right',
- v_align='center',
- maxwidth=200,
- scale=0.8,
- color=ba.app.infotextcolor,
- position=(210, v - 9),
- text=party_name_text)
- self._internet_host_name_text = ba.textwidget(
- parent=self._tab_container,
- editable=True,
- size=(535, 40),
- position=(230, v - 30),
- text=ba.app.config.get('Public Party Name', ''),
- maxwidth=494,
- shadow=0.3,
- flatness=1.0,
- description=party_name_text,
- autoselect=True,
- v_align='center',
- corner_scale=1.0)
-
- v -= 60
- self._internet_host_max_party_size_label = ba.textwidget(
- parent=self._tab_container,
- size=(0, 0),
- h_align='right',
- v_align='center',
- maxwidth=200,
- scale=0.8,
- color=ba.app.infotextcolor,
- position=(210, v - 9),
- text=ba.Lstr(resource='maxPartySizeText',
- fallback_resource='maxConnectionsText'))
- self._internet_host_max_party_size_value = ba.textwidget(
- parent=self._tab_container,
- size=(0, 0),
- h_align='center',
- v_align='center',
- scale=1.2,
- color=(1, 1, 1),
- position=(240, v - 9),
- text=str(_ba.get_public_party_max_size()))
- btn1 = self._internet_host_max_party_size_minus_button = (
- ba.buttonwidget(
- parent=self._tab_container,
- size=(40, 40),
- on_activate_call=ba.WeakCall(
- self._on_max_public_party_size_minus_press),
- position=(280, v - 26),
- label='-',
- autoselect=True))
- btn2 = self._internet_host_max_party_size_plus_button = (
- ba.buttonwidget(parent=self._tab_container,
- size=(40, 40),
- on_activate_call=ba.WeakCall(
- self._on_max_public_party_size_plus_press),
- position=(350, v - 26),
- label='+',
- autoselect=True))
- v -= 50
- v -= 70
- if is_public_enabled:
- label = ba.Lstr(
- resource='gatherWindow.makePartyPrivateText',
- fallback_resource='gatherWindow.stopAdvertisingText')
- else:
- label = ba.Lstr(
- resource='gatherWindow.makePartyPublicText',
- fallback_resource='gatherWindow.startAdvertisingText')
- self._internet_host_toggle_button = ba.buttonwidget(
- parent=self._tab_container,
- label=label,
- size=(400, 80),
- on_activate_call=self._on_stop_internet_advertising_press
- if is_public_enabled else
- self._on_start_internet_advertizing_press,
- position=(c_width * 0.5 - 200, v),
- autoselect=True,
- up_widget=btn2)
- ba.widget(edit=self._internet_host_name_text, down_widget=btn2)
- ba.widget(edit=btn2, up_widget=self._internet_host_name_text)
- ba.widget(edit=btn1, up_widget=self._internet_host_name_text)
- ba.widget(edit=self._internet_join_text,
- down_widget=self._internet_host_name_text)
- v -= 10
- self._internet_host_status_text = ba.textwidget(
- parent=self._tab_container,
- text=ba.Lstr(resource=self._r + '.partyStatusNotPublicText'),
- size=(0, 0),
- scale=0.7,
- flatness=1.0,
- shadow=0.0,
- h_align='center',
- v_align='top',
- maxwidth=c_width,
- color=(0.6, 0.6, 0.6),
- position=(c_width * 0.5, v))
- v -= 90
- self._internet_host_dedicated_server_info_text = ba.textwidget(
- parent=self._tab_container,
- text=ba.Lstr(resource=self._r + '.dedicatedServerInfoText'),
- size=(0, 0),
- scale=0.7,
- flatness=1.0,
- shadow=0.0,
- h_align='center',
- v_align='center',
- maxwidth=c_width * 0.9,
- color=ba.app.infotextcolor,
- position=(c_width * 0.5, v))
-
- # If public sharing is already on,
- # launch a status-check immediately.
- if _ba.get_public_party_enabled():
- self._do_internet_status_check()
-
- # Now add a lock icon overlay for if we don't have pro.
- icon = self._internet_lock_icon
- if icon and self._internet_lock_icon:
- self._internet_lock_icon.delete() # Kill any existing.
- self._internet_lock_icon = ba.imagewidget(
- parent=self._tab_container,
- position=(c_width * 0.5 - 60, c_height * 0.5 - 50),
- size=(120, 120),
- opacity=0.0 if not self._is_internet_locked() else 0.5,
- texture=ba.gettexture('lock'))
-
- def _is_internet_locked(self) -> bool:
- from ba.internal import have_pro
- if _ba.get_account_misc_read_val('ilck', False):
- return not have_pro()
- return False
-
- def _on_max_public_party_size_minus_press(self) -> None:
- val = _ba.get_public_party_max_size()
- val -= 1
- if val < 1:
- val = 1
- _ba.set_public_party_max_size(val)
- ba.textwidget(edit=self._internet_host_max_party_size_value,
- text=str(val))
-
- def _on_max_public_party_size_plus_press(self) -> None:
- val = _ba.get_public_party_max_size()
- val += 1
- _ba.set_public_party_max_size(val)
- ba.textwidget(edit=self._internet_host_max_party_size_value,
- text=str(val))
-
- def _on_public_party_query_result(
- self, result: Optional[Dict[str, Any]]) -> None:
- with ba.Context('ui'):
- # Any time we get any result at all, kill our loading status.
- status_text = self._internet_join_status_text
- if status_text:
- # Don't show results if not signed in
- # (probably didn't get any anyway).
- if _ba.get_account_state() != 'signed_in':
- ba.textwidget(edit=status_text,
- text=ba.Lstr(resource='notSignedInText'))
- else:
- if result is None:
- ba.textwidget(edit=status_text,
- text=ba.Lstr(resource='errorText'))
- else:
- ba.textwidget(edit=status_text, text='')
-
- if result is not None:
- parties_in = result['l']
- else:
- parties_in = []
-
- for partyval in list(self._public_parties.values()):
- partyval['claimed'] = False
-
- for party_in in parties_in:
- # Party is indexed by (ADDR)_(PORT)
- party_key = party_in['a'] + '_' + str(party_in['p'])
- party = self._public_parties.get(party_key)
- if party is None:
- # If this party is new to us, init it.
- index = self._next_public_party_entry_index
- self._next_public_party_entry_index = index + 1
- party = self._public_parties[party_key] = {
- 'address':
- party_in.get('a'),
- 'next_ping_time':
- ba.time(ba.TimeType.REAL) + 0.001 * party_in['pd'],
- 'ping':
- None,
- 'index':
- index,
- }
-
- # Now, new or not, update its values.
- party['queue'] = party_in.get('q')
- party['port'] = party_in.get('p')
- party['name'] = party_in['n']
- party['size'] = party_in['s']
- party['language'] = party_in['l']
- party['size_max'] = party_in['sm']
- party['claimed'] = True
- # (server provides this in milliseconds; we use seconds)
- party['ping_interval'] = 0.001 * party_in['pi']
- party['stats_addr'] = party_in['sa']
-
- # Prune unclaimed party entries.
- self._public_parties = {
- key: val
- for key, val in list(self._public_parties.items())
- if val['claimed']
- }
-
- self._rebuild_public_party_list()
-
- def _rebuild_public_party_list(self) -> None:
- # pylint: disable=too-many-branches
- # pylint: disable=too-many-locals
- # pylint: disable=too-many-statements
- cur_time = ba.time(ba.TimeType.REAL)
- if self._first_public_party_list_rebuild_time is None:
- self._first_public_party_list_rebuild_time = cur_time
-
- # Update faster for the first few seconds;
- # then ease off to keep the list from jumping around.
- since_first = cur_time - self._first_public_party_list_rebuild_time
- wait_time = (1.0 if since_first < 2.0 else
- 2.5 if since_first < 10.0 else 5.0)
- assert self._last_public_party_list_rebuild_time is not None
- if cur_time - self._last_public_party_list_rebuild_time < wait_time:
- return
- self._last_public_party_list_rebuild_time = cur_time
-
- # First off, check for the existence of our column widget;
- # if we don't have this, we're done.
- columnwidget = self._internet_host_columnwidget
- if not columnwidget:
- return
-
- with ba.Context('ui'):
-
- # Now kill and recreate all widgets.
- for widget in columnwidget.get_children():
- widget.delete()
-
- # Sort - show queue-enabled ones first and sort by lowest ping.
- ordered_parties = sorted(
- list(self._public_parties.values()),
- key=lambda p: (
- p['queue'] is None, # Show non-queued last.
- p['ping'] if p['ping'] is not None else 999999,
- p['index']))
- existing_selection = self._public_party_list_selection
- first = True
-
- sub_scroll_width = 830
- lineheight = 42
- sub_scroll_height = lineheight * len(ordered_parties) + 50
- ba.containerwidget(edit=columnwidget,
- size=(sub_scroll_width, sub_scroll_height))
-
- # Ew; this rebuilding generates deferred selection callbacks
- # so we need to generated deferred ignore notices for ourself.
- def refresh_on() -> None:
- self._refreshing_public_party_list = True
-
- ba.pushcall(refresh_on)
-
- # Janky - allow escaping if there's nothing in us.
- ba.containerwidget(edit=self._internet_host_scrollwidget,
- claims_up_down=(len(ordered_parties) > 0))
-
- for i, party in enumerate(ordered_parties):
- hpos = 20
- vpos = sub_scroll_height - lineheight * i - 50
- party['name_widget'] = ba.textwidget(
- text=ba.Lstr(value=party['name']),
- parent=columnwidget,
- size=(sub_scroll_width * 0.63, 20),
- position=(0 + hpos, 4 + vpos),
- selectable=True,
- on_select_call=ba.WeakCall(
- self._set_public_party_selection,
- (party['address'], 'name')),
- on_activate_call=ba.WeakCall(
- self._on_public_party_activate, party),
- click_activate=True,
- maxwidth=sub_scroll_width * 0.45,
- corner_scale=1.4,
- autoselect=True,
- color=(1, 1, 1, 0.3 if party['ping'] is None else 1.0),
- h_align='left',
- v_align='center')
- ba.widget(edit=party['name_widget'],
- left_widget=self._internet_join_text,
- show_buffer_top=64.0,
- show_buffer_bottom=64.0)
- if existing_selection == (party['address'], 'name'):
- ba.containerwidget(edit=columnwidget,
- selected_child=party['name_widget'])
- if bool(False):
- party['language_widget'] = ba.textwidget(
- text=ba.Lstr(translate=('languages',
- party['language'])),
- parent=columnwidget,
- size=(0, 0),
- position=(sub_scroll_width * 0.73 + hpos, 20 + vpos),
- maxwidth=sub_scroll_width * 0.13,
- scale=0.7,
- color=(0.8, 0.8, 0.8),
- h_align='center',
- v_align='center')
- if party['stats_addr'] != '':
- url = party['stats_addr'].replace(
- '${ACCOUNT}',
- _ba.get_account_misc_read_val_2(
- 'resolvedAccountID', 'UNKNOWN'))
- party['stats_button'] = ba.buttonwidget(
- color=(0.3, 0.6, 0.94),
- textcolor=(1.0, 1.0, 1.0),
- label=ba.Lstr(resource='statsText'),
- parent=columnwidget,
- autoselect=True,
- on_activate_call=ba.Call(ba.open_url, url),
- on_select_call=ba.WeakCall(
- self._set_public_party_selection,
- (party['address'], 'stats_button')),
- size=(120, 40),
- position=(sub_scroll_width * 0.66 + hpos, 1 + vpos),
- scale=0.9)
- if existing_selection == (party['address'],
- 'stats_button'):
- ba.containerwidget(
- edit=columnwidget,
- selected_child=party['stats_button'])
- else:
- if 'stats_button' in party:
- del party['stats_button']
-
- if first:
- if 'stats_button' in party:
- ba.widget(edit=party['stats_button'],
- up_widget=self._internet_join_text)
- if 'name_widget' in party:
- ba.widget(edit=party['name_widget'],
- up_widget=self._internet_join_text)
- first = False
-
- party['size_widget'] = ba.textwidget(
- text=str(party['size']) + '/' + str(party['size_max']),
- parent=columnwidget,
- size=(0, 0),
- position=(sub_scroll_width * 0.86 + hpos, 20 + vpos),
- scale=0.7,
- color=(0.8, 0.8, 0.8),
- h_align='right',
- v_align='center')
- party['ping_widget'] = ba.textwidget(
- parent=columnwidget,
- size=(0, 0),
- position=(sub_scroll_width * 0.94 + hpos, 20 + vpos),
- scale=0.7,
- h_align='right',
- v_align='center')
- if party['ping'] is None:
- ba.textwidget(edit=party['ping_widget'],
- text='-',
- color=(0.5, 0.5, 0.5))
- else:
- ping_good = _ba.get_account_misc_read_val('pingGood', 100)
- ping_med = _ba.get_account_misc_read_val('pingMed', 500)
- ba.textwidget(edit=party['ping_widget'],
- text=str(party['ping']),
- color=(0, 1,
- 0) if party['ping'] <= ping_good else
- (1, 1, 0) if party['ping'] <= ping_med else
- (1, 0, 0))
-
- # So our selection callbacks can start firing..
- def refresh_on2() -> None:
- self._refreshing_public_party_list = False
-
- ba.pushcall(refresh_on2)
-
- def _on_public_party_activate(self, party: Dict[str, Any]) -> None:
- from bastd.ui import purchase
- from bastd.ui import account
- if party['queue'] is not None:
- from bastd.ui import partyqueue
- ba.playsound(ba.getsound('swish'))
- partyqueue.PartyQueueWindow(party['queue'], party['address'],
- party['port'])
- else:
- address = party['address']
- port = party['port']
- if self._is_internet_locked():
- if _ba.get_account_state() != 'signed_in':
- account.show_sign_in_prompt()
- else:
- purchase.PurchaseWindow(items=['pro'])
- return
- # rate limit this a bit
- now = time.time()
- last_connect_time = self._last_public_party_connect_attempt_time
- if last_connect_time is None or now - last_connect_time > 2.0:
- _ba.connect_to_party(address, port=port)
- self._last_public_party_connect_attempt_time = now
-
- def _set_public_party_selection(self, sel: Tuple[str, str]) -> None:
- if self._refreshing_public_party_list:
- return
- self._public_party_list_selection = sel
-
- def _update_internet_tab(self) -> None:
- # pylint: disable=too-many-statements
-
- # 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:
- return
-
- # If we've got a party-name text widget, keep its value plugged
- # into our public host name.
- text = self._internet_host_name_text
- if text:
- name = cast(str,
- ba.textwidget(query=self._internet_host_name_text))
- _ba.set_public_party_name(name)
-
- # Show/hide the lock icon depending on if we've got pro.
- icon = self._internet_lock_icon
- if icon:
- if self._is_internet_locked():
- ba.imagewidget(edit=icon, opacity=0.5)
- else:
- ba.imagewidget(edit=icon, opacity=0.0)
-
- if self._internet_tab == 'join':
- now = ba.time(ba.TimeType.REAL)
- if (now - self._internet_join_last_refresh_time > 0.001 *
- _ba.get_account_misc_read_val('pubPartyRefreshMS', 10000)):
- self._internet_join_last_refresh_time = now
- app = ba.app
- _ba.add_transaction(
- {
- 'type': 'PUBLIC_PARTY_QUERY',
- 'proto': app.protocol_version,
- 'lang': app.language
- },
- callback=ba.WeakCall(self._on_public_party_query_result))
- _ba.run_transactions()
-
- # Go through our existing public party entries firing off pings
- # for any that have timed out.
- for party in list(self._public_parties.values()):
- if (party['next_ping_time'] <= now
- and ba.app.ping_thread_count < 15):
-
- # Make sure to fully catch up and not to multi-ping if
- # we're way behind somehow.
- while party['next_ping_time'] <= now:
- # Crank the interval up for high-latency parties to
- # save us some work.
- mult = 1
- if party['ping'] is not None:
- mult = (10 if party['ping'] > 300 else
- 5 if party['ping'] > 150 else 2)
- party[
- 'next_ping_time'] += party['ping_interval'] * mult
-
- class PingThread(threading.Thread):
- """Thread for sending out pings."""
-
- def __init__(self, address: str, port: int,
- call: Callable[[str, int, Optional[int]],
- Optional[int]]):
- super().__init__()
- self._address = address
- self._port = port
- self._call = call
-
- def run(self) -> None:
- ba.app.ping_thread_count += 1
- try:
- import socket
- from ba.internal import get_ip_address_type
- socket_type = get_ip_address_type(
- self._address)
- sock = socket.socket(socket_type,
- socket.SOCK_DGRAM)
- sock.connect((self._address, self._port))
-
- accessible = False
- starttime = time.time()
-
- # Send a few pings and wait a second for
- # a response.
- sock.settimeout(1)
- for _i in range(3):
- sock.send(b'\x0b')
- result: Optional[bytes]
- try:
- # 11: BA_PACKET_SIMPLE_PING
- result = sock.recv(10)
- except Exception:
- result = None
- if result == b'\x0c':
- # 12: BA_PACKET_SIMPLE_PONG
- accessible = True
- break
- time.sleep(1)
- sock.close()
- ping = int((time.time() - starttime) * 1000.0)
- ba.pushcall(ba.Call(
- self._call, self._address, self._port,
- ping if accessible else None),
- from_other_thread=True)
- except OSError as exc:
- import errno
-
- # Ignore harmless errors.
- if exc.errno == errno.EHOSTUNREACH:
- pass
- elif exc.errno == errno.EADDRNOTAVAIL:
- if self._port == 0:
- # This has happened. Ignore.
- pass
- elif ba.do_once():
- print(
- f'Got EADDRNOTAVAIL on gather ping'
- f' for addr {self._address}'
- f' port {self._port}.')
- else:
- ba.print_exception('Error on gather ping.',
- once=True)
- except Exception:
- ba.print_exception('Error on gather ping',
- once=True)
- ba.app.ping_thread_count -= 1
-
- PingThread(party['address'], party['port'],
- ba.WeakCall(self._ping_callback)).start()
-
- def _ping_callback(self, address: str, port: Optional[int],
- result: Optional[int]) -> None:
- # Look for a widget corresponding to this target.
- # If we find one, update our list.
- party = self._public_parties.get(address + '_' + str(port))
- if party is not None:
- # We now smooth ping a bit to reduce jumping around in the list
- # (only where pings are relatively good).
- current_ping = party.get('ping')
- if (current_ping is not None and result is not None
- and result < 150):
- smoothing = 0.7
- party['ping'] = int(smoothing * current_ping +
- (1.0 - smoothing) * result)
- else:
- party['ping'] = result
-
- # This can happen if we switch away and then back to the
- # client tab while pings are in flight.
- if 'ping_widget' not in party:
- pass
- elif party['ping_widget']:
- self._rebuild_public_party_list()
-
- def _do_internet_status_check(self) -> None:
- from ba.internal import serverget
- 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))
-
- def _on_start_internet_advertizing_press(self) -> None:
- from bastd.ui import account
- from bastd.ui import purchase
- if _ba.get_account_state() != 'signed_in':
- account.show_sign_in_prompt()
- return
-
- # Requires sign-in and pro.
- if self._is_internet_locked():
- if _ba.get_account_state() != 'signed_in':
- account.show_sign_in_prompt()
- else:
- purchase.PurchaseWindow(items=['pro'])
- return
-
- name = cast(str, ba.textwidget(query=self._internet_host_name_text))
- if name == '':
- ba.screenmessage(ba.Lstr(resource='internal.invalidNameErrorText'),
- color=(1, 0, 0))
- ba.playsound(ba.getsound('error'))
- return
- _ba.set_public_party_name(name)
- cfg = ba.app.config
- cfg['Public Party Name'] = name
- cfg.commit()
- ba.playsound(ba.getsound('shieldUp'))
- _ba.set_public_party_enabled(True)
-
- # In GUI builds we want to authenticate clients only when hosting
- # public parties.
- _ba.set_authenticate_clients(True)
-
- self._do_internet_status_check()
- ba.buttonwidget(
- edit=self._internet_host_toggle_button,
- label=ba.Lstr(
- resource='gatherWindow.makePartyPrivateText',
- fallback_resource='gatherWindow.stopAdvertisingText'),
- on_activate_call=self._on_stop_internet_advertising_press)
-
- def _on_public_party_accessible_response(
- self, data: Optional[Dict[str, Any]]) -> None:
- # If we've got status text widgets, update them.
- 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))
- else:
- if not data.get('accessible', False):
- ex_line: Union[str, ba.Lstr]
- if self._internet_local_address is not None:
- ex_line = ba.Lstr(
- value='\n${A} ${B}',
- subs=[('${A}',
- ba.Lstr(resource=self._r +
- '.manualYourLocalAddressText')),
- ('${B}', self._internet_local_address)])
- else:
- ex_line = ''
- ba.textwidget(
- edit=text,
- text=ba.Lstr(
- value='${A}\n${B}${C}',
- subs=[('${A}',
- ba.Lstr(resource=self._r +
- '.partyStatusNotJoinableText')),
- ('${B}',
- ba.Lstr(resource=self._r +
- '.manualRouterForwardingText',
- subs=[('${PORT}',
- str(_ba.get_game_port()))])),
- ('${C}', ex_line)]),
- color=(1, 0, 0))
- else:
- ba.textwidget(edit=text,
- text=ba.Lstr(resource=self._r +
- '.partyStatusJoinableText'),
- color=(0, 1, 0))
-
- def _on_stop_internet_advertising_press(self) -> None:
- _ba.set_public_party_enabled(False)
-
- # In GUI builds we want to authenticate clients only when hosting
- # public parties.
- _ba.set_authenticate_clients(False)
-
- 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.buttonwidget(
- edit=self._internet_host_toggle_button,
- label=ba.Lstr(
- resource='gatherWindow.makePartyPublicText',
- fallback_resource='gatherWindow.startAdvertisingText'),
- on_activate_call=self._on_start_internet_advertizing_press)
-
- def _access_check_update(self, t_addr: ba.Widget, t_accessible: ba.Widget,
- t_accessible_extra: ba.Widget) -> None:
- from ba.internal import serverget
-
- # If we don't have an outstanding query, start one..
- assert self._doing_access_check is not None
- assert self._access_check_count is not None
- if not self._doing_access_check and self._access_check_count < 100:
- self._doing_access_check = True
- self._access_check_count += 1
- 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))
-
- def _on_accessible_response(self, data: Optional[Dict[str, Any]]) -> None:
- t_addr = self._t_addr
- t_accessible = self._t_accessible
- t_accessible_extra = self._t_accessible_extra
- self._doing_access_check = False
- color_bad = (1, 1, 0)
- color_good = (0, 1, 0)
- if data is None or 'address' not in data or 'accessible' not in data:
- if t_addr:
- ba.textwidget(edit=t_addr,
- text=ba.Lstr(resource=self._r +
- '.noConnectionText'),
- color=color_bad)
- if t_accessible:
- ba.textwidget(edit=t_accessible,
- text=ba.Lstr(resource=self._r +
- '.noConnectionText'),
- color=color_bad)
- if t_accessible_extra:
- ba.textwidget(edit=t_accessible_extra,
- text='',
- color=color_bad)
- return
- if t_addr:
- ba.textwidget(edit=t_addr, text=data['address'], color=color_good)
- if t_accessible:
- if data['accessible']:
- ba.textwidget(edit=t_accessible,
- text=ba.Lstr(resource=self._r +
- '.manualJoinableYesText'),
- color=color_good)
- if t_accessible_extra:
- ba.textwidget(edit=t_accessible_extra,
- text='',
- color=color_good)
- else:
- ba.textwidget(
- edit=t_accessible,
- text=ba.Lstr(resource=self._r +
- '.manualJoinableNoWithAsteriskText'),
- color=color_bad)
- if t_accessible_extra:
- ba.textwidget(edit=t_accessible_extra,
- text=ba.Lstr(resource=self._r +
- '.manualRouterForwardingText',
- subs=[('${PORT}',
- str(_ba.get_game_port()))
- ]),
- color=color_bad)
-
- def _save_state(self) -> None:
- try:
- sel = self._root_widget.get_selected_child()
- if sel == self._back_button:
- sel_name = 'Back'
- elif sel in list(self._tab_buttons.values()):
- sel_name = 'Tab:' + list(self._tab_buttons.keys())[list(
- self._tab_buttons.values()).index(sel)]
- elif sel == self._tab_container:
- sel_name = 'TabContainer'
- else:
- raise Exception('unrecognized selection: ' + str(sel))
- ba.app.window_states[self.__class__.__name__] = {
- 'sel_name': sel_name,
- 'tab': self._current_tab,
- 'internet_tab': self._internet_tab
- }
- except Exception:
- ba.print_exception('error saving state for', self.__class__)
-
- def _restore_state(self) -> None:
- try:
- winstate = ba.app.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)
- if current_tab is None or current_tab not in self._tab_buttons:
- current_tab = 'about'
- self._set_tab(current_tab)
- if sel_name == 'Back':
- sel = self._back_button
- elif sel_name == 'TabContainer':
- sel = self._tab_container
- elif isinstance(sel_name, str) and sel_name.startswith('Tab:'):
- sel = self._tab_buttons[sel_name.split(':')[-1]]
- else:
- 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__)
-
- def _back(self) -> None:
- from bastd.ui import mainmenu
- 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())
diff --git a/assets/src/ba_data/python/bastd/ui/gather/__init__.py b/assets/src/ba_data/python/bastd/ui/gather/__init__.py
new file mode 100644
index 00000000..3d21747c
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/ui/gather/__init__.py
@@ -0,0 +1,331 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Provides UI for inviting/joining friends."""
+
+from __future__ import annotations
+
+import weakref
+from enum import Enum
+from typing import TYPE_CHECKING
+
+import _ba
+import ba
+from bastd.ui.tabs import TabRow
+
+if TYPE_CHECKING:
+ from typing import (Any, Optional, Tuple, Dict, List, Union, Callable,
+ Type)
+
+
+class GatherTab:
+ """Defines a tab for use in the gather UI."""
+
+ def __init__(self, window: GatherWindow) -> None:
+ self._window = weakref.ref(window)
+
+ @property
+ def window(self) -> GatherWindow:
+ """The GatherWindow that this tab belongs to."""
+ window = self._window()
+ if window is None:
+ raise ba.NotFoundError("GatherTab's window no longer exists.")
+ return window
+
+ def on_activate(
+ self,
+ parent_widget: ba.Widget,
+ tab_button: ba.Widget,
+ region_width: float,
+ region_height: float,
+ region_left: float,
+ region_bottom: float,
+ ) -> ba.Widget:
+ """Called when the tab becomes the active one.
+
+ The tab should create and return a container widget covering the
+ specified region.
+ """
+
+ def on_deactivate(self) -> None:
+ """Called when the tab will no longer be the active one."""
+
+ def save_state(self) -> None:
+ """Called when the parent window is saving state."""
+
+ def restore_state(self) -> None:
+ """Called when the parent window is restoring state."""
+
+
+class GatherWindow(ba.Window):
+ """Window for joining/inviting friends."""
+
+ class TabID(Enum):
+ """Our available tab types."""
+ ABOUT = 'about'
+ INTERNET = 'internet'
+ PRIVATE = 'private'
+ NEARBY = 'nearby'
+ MANUAL = 'manual'
+
+ def __init__(self,
+ transition: Optional[str] = 'in_right',
+ origin_widget: ba.Widget = None):
+ # pylint: disable=too-many-statements
+ # pylint: disable=too-many-locals
+ # pylint: disable=cyclic-import
+ from bastd.ui.gather.abouttab import AboutGatherTab
+ from bastd.ui.gather.manualtab import ManualGatherTab
+ from bastd.ui.gather.privatetab import PrivateGatherTab
+ from bastd.ui.gather.publictab import PublicGatherTab
+ from bastd.ui.gather.nearbytab import NearbyGatherTab
+
+ ba.set_analytics_screen('Gather Window')
+ 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
+ ba.app.ui.set_main_menu_location('Gather')
+ _ba.set_party_icon_always_visible(True)
+ 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
+ 680 if uiscale is ba.UIScale.MEDIUM else 800)
+ self._current_tab: Optional[GatherWindow.TabID] = None
+ extra_top = 20 if uiscale is ba.UIScale.SMALL else 0
+ self._r = 'gatherWindow'
+
+ 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 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 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
+ else:
+ self._back_button = btn = ba.buttonwidget(
+ parent=self._root_widget,
+ position=(70 + x_offs, self._height - 74),
+ size=(140, 60),
+ scale=1.1,
+ autoselect=True,
+ label=ba.Lstr(resource='backText'),
+ button_type='back',
+ on_activate_call=self._back)
+ ba.containerwidget(edit=self._root_widget, cancel_button=btn)
+ ba.buttonwidget(edit=btn,
+ button_type='backSmall',
+ position=(70 + x_offs, self._height - 78),
+ size=(60, 60),
+ label=ba.charstr(ba.SpecialChar.BACK))
+
+ condensed = uiscale is not ba.UIScale.LARGE
+ t_offs_y = (0 if not condensed else
+ 25 if uiscale is ba.UIScale.MEDIUM else 17)
+ ba.textwidget(parent=self._root_widget,
+ position=(self._width * 0.5,
+ self._height - 42 + t_offs_y),
+ size=(0, 0),
+ color=ba.app.ui.title_color,
+ scale=(1.5 if not condensed else
+ 1.0 if uiscale is ba.UIScale.MEDIUM else 0.6),
+ h_align='center',
+ v_align='center',
+ text=ba.Lstr(resource=self._r + '.titleText'),
+ maxwidth=550)
+
+ scroll_buffer_h = 130 + 2 * x_offs
+ tab_buffer_h = ((320 if condensed else 250) + 2 * x_offs)
+
+ # Build up the set of tabs we want.
+ tabdefs: List[Tuple[GatherWindow.TabID, ba.Lstr]] = [
+ (self.TabID.ABOUT, ba.Lstr(resource=self._r + '.aboutText'))
+ ]
+ if _ba.get_account_misc_read_val('enablePublicParties', True):
+ tabdefs.append((self.TabID.INTERNET,
+ ba.Lstr(resource=self._r + '.publicText')))
+ tabdefs.append(
+ (self.TabID.PRIVATE, ba.Lstr(resource=self._r + '.privateText')))
+ tabdefs.append(
+ (self.TabID.NEARBY, ba.Lstr(resource=self._r + '.nearbyText')))
+ tabdefs.append(
+ (self.TabID.MANUAL, ba.Lstr(resource=self._r + '.manualText')))
+
+ # On small UI, push our tabs up closer to the top of the screen to
+ # save a bit of space.
+ tabs_top_extra = 42 if condensed else 0
+ self._tab_row = TabRow(self._root_widget,
+ tabdefs,
+ pos=(tab_buffer_h * 0.5,
+ self._height - 130 + tabs_top_extra),
+ size=(self._width - tab_buffer_h, 50),
+ on_select_call=ba.WeakCall(self._set_tab))
+
+ # Now instantiate handlers for these tabs.
+ tabtypes: Dict[GatherWindow.TabID, Type[GatherTab]] = {
+ self.TabID.ABOUT: AboutGatherTab,
+ self.TabID.MANUAL: ManualGatherTab,
+ self.TabID.PRIVATE: PrivateGatherTab,
+ self.TabID.INTERNET: PublicGatherTab,
+ self.TabID.NEARBY: NearbyGatherTab
+ }
+ self._tabs: Dict[GatherWindow.TabID, GatherTab] = {}
+ for tab_id in self._tab_row.tabs:
+ tabtype = tabtypes.get(tab_id)
+ if tabtype is not None:
+ self._tabs[tab_id] = tabtype(self)
+
+ if ba.app.ui.use_toolbars:
+ ba.widget(edit=self._tab_row.tabs[tabdefs[-1][0]].button,
+ right_widget=_ba.get_special_widget('party_button'))
+ if uiscale is ba.UIScale.SMALL:
+ ba.widget(edit=self._tab_row.tabs[tabdefs[0][0]].button,
+ left_widget=_ba.get_special_widget('back_button'))
+
+ self._scroll_width = self._width - scroll_buffer_h
+ self._scroll_height = self._height - 180.0 + tabs_top_extra
+
+ self._scroll_left = (self._width - self._scroll_width) * 0.5
+ self._scroll_bottom = (self._height - self._scroll_height - 79 - 48 +
+ tabs_top_extra)
+ buffer_h = 10
+ buffer_v = 4
+
+ # Not actually using a scroll widget anymore; just an image.
+ ba.imagewidget(parent=self._root_widget,
+ position=(self._scroll_left - buffer_h,
+ self._scroll_bottom - buffer_v),
+ size=(self._scroll_width + 2 * buffer_h,
+ self._scroll_height + 2 * buffer_v),
+ texture=ba.gettexture('scrollWidget'),
+ model_transparent=ba.getmodel('softEdgeOutside'))
+ self._tab_container: Optional[ba.Widget] = None
+
+ self._restore_state()
+
+ def __del__(self) -> None:
+ _ba.set_party_icon_always_visible(False)
+
+ def playlist_select(self, origin_widget: ba.Widget) -> None:
+ """Called by the private-hosting tab to select a playlist."""
+ from bastd.ui.play import PlayWindow
+ self._save_state()
+ ba.containerwidget(edit=self._root_widget, transition='out_left')
+ ba.app.ui.selecting_private_party_playlist = True
+ ba.app.ui.set_main_menu_window(
+ PlayWindow(origin_widget=origin_widget).get_root_widget())
+
+ def _set_tab(self, tab_id: TabID) -> None:
+ if self._current_tab is tab_id:
+ return
+ prev_tab_id = self._current_tab
+ self._current_tab = tab_id
+
+ # We wanna preserve our current tab between runs.
+ cfg = ba.app.config
+ cfg['Gather Tab'] = tab_id.value
+ cfg.commit()
+
+ # Update tab colors based on which is selected.
+ self._tab_row.update_appearance(tab_id)
+
+ if prev_tab_id is not None:
+ prev_tab = self._tabs.get(prev_tab_id)
+ if prev_tab is not None:
+ prev_tab.on_deactivate()
+
+ # Clear up prev container if it hasn't been done.
+ if self._tab_container:
+ self._tab_container.delete()
+
+ tab = self._tabs.get(tab_id)
+ if tab is not None:
+ self._tab_container = tab.on_activate(
+ self._root_widget,
+ self._tab_row.tabs[tab_id].button,
+ self._scroll_width,
+ self._scroll_height,
+ self._scroll_left,
+ self._scroll_bottom,
+ )
+ return
+
+ def _save_state(self) -> None:
+ try:
+ for tab in self._tabs.values():
+ tab.save_state()
+
+ sel = self._root_widget.get_selected_child()
+ selected_tab_ids = [
+ tab_id for tab_id, tab in self._tab_row.tabs.items()
+ if sel == tab.button
+ ]
+ if sel == self._back_button:
+ sel_name = 'Back'
+ elif selected_tab_ids:
+ assert len(selected_tab_ids) == 1
+ sel_name = f'Tab:{selected_tab_ids[0].value}'
+ elif sel == self._tab_container:
+ sel_name = 'TabContainer'
+ else:
+ raise ValueError(f'unrecognized selection: \'{sel}\'')
+ ba.app.ui.window_states[type(self)] = {
+ 'sel_name': sel_name,
+ }
+ except Exception:
+ ba.print_exception(f'Error saving state for {self}.')
+
+ def _restore_state(self) -> None:
+ from efro.util import enum_by_value
+ try:
+ for tab in self._tabs.values():
+ tab.restore_state()
+
+ sel: Optional[ba.Widget]
+ winstate = ba.app.ui.window_states.get(type(self), {})
+ sel_name = winstate.get('sel_name', None)
+ assert isinstance(sel_name, (str, type(None)))
+ current_tab = self.TabID.ABOUT
+ gather_tab_val = ba.app.config.get('Gather Tab')
+ try:
+ stored_tab = enum_by_value(self.TabID, gather_tab_val)
+ if stored_tab in self._tab_row.tabs:
+ current_tab = stored_tab
+ except ValueError:
+ pass
+ self._set_tab(current_tab)
+ if sel_name == 'Back':
+ sel = self._back_button
+ elif sel_name == 'TabContainer':
+ sel = self._tab_container
+ elif isinstance(sel_name, str) and sel_name.startswith('Tab:'):
+ try:
+ sel_tab_id = enum_by_value(self.TabID,
+ sel_name.split(':')[-1])
+ except ValueError:
+ sel_tab_id = self.TabID.ABOUT
+ sel = self._tab_row.tabs[sel_tab_id].button
+ else:
+ sel = self._tab_row.tabs[current_tab].button
+ ba.containerwidget(edit=self._root_widget, selected_child=sel)
+ except Exception:
+ ba.print_exception('Error restoring gather-win state.')
+
+ def _back(self) -> None:
+ from bastd.ui.mainmenu import MainMenuWindow
+ self._save_state()
+ ba.containerwidget(edit=self._root_widget,
+ transition=self._transition_out)
+ ba.app.ui.set_main_menu_window(
+ MainMenuWindow(transition='in_left').get_root_widget())
diff --git a/assets/src/ba_data/python/bastd/ui/gather/abouttab.py b/assets/src/ba_data/python/bastd/ui/gather/abouttab.py
new file mode 100644
index 00000000..a76eb11b
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/ui/gather/abouttab.py
@@ -0,0 +1,110 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Defines the about tab in the gather UI."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import ba
+import _ba
+from bastd.ui.gather import GatherTab
+
+if TYPE_CHECKING:
+ from typing import Optional
+ from bastd.ui.gather import GatherWindow
+
+
+class AboutGatherTab(GatherTab):
+ """The about tab in the gather UI"""
+
+ def __init__(self, window: GatherWindow) -> None:
+ super().__init__(window)
+ self._container: Optional[ba.Widget] = None
+
+ def on_activate(
+ self,
+ parent_widget: ba.Widget,
+ tab_button: ba.Widget,
+ region_width: float,
+ region_height: float,
+ region_left: float,
+ region_bottom: float,
+ ) -> ba.Widget:
+ message = ba.Lstr(
+ resource='gatherWindow.aboutDescriptionText',
+ subs=[('${PARTY}', ba.charstr(ba.SpecialChar.PARTY_ICON)),
+ ('${BUTTON}', ba.charstr(ba.SpecialChar.TOP_BUTTON))],
+ )
+
+ # Let's not talk about sharing in vr-mode; its tricky to fit more
+ # than one head in a VR-headset ;-)
+ if not ba.app.vr_mode:
+ message = ba.Lstr(
+ value='${A}\n\n${B}',
+ subs=[('${A}', message),
+ ('${B}',
+ ba.Lstr(resource='gatherWindow.'
+ 'aboutDescriptionLocalMultiplayerExtraText'))])
+ string_height = 400
+ include_invite = True
+ msc_scale = 1.1
+ c_height_2 = min(region_height, string_height * msc_scale + 100)
+ try_tickets = _ba.get_account_misc_read_val('friendTryTickets', None)
+ if try_tickets is None:
+ include_invite = False
+ self._container = ba.containerwidget(
+ parent=parent_widget,
+ position=(region_left,
+ region_bottom + (region_height - c_height_2) * 0.5),
+ size=(region_width, c_height_2),
+ background=False,
+ selectable=include_invite)
+ ba.widget(edit=self._container, up_widget=tab_button)
+
+ ba.textwidget(parent=self._container,
+ position=(region_width * 0.5, c_height_2 *
+ (0.58 if include_invite else 0.5)),
+ color=(0.6, 1.0, 0.6),
+ scale=msc_scale,
+ size=(0, 0),
+ maxwidth=region_width * 0.9,
+ max_height=c_height_2 * (0.7 if include_invite else 0.9),
+ h_align='center',
+ v_align='center',
+ text=message)
+
+ if include_invite:
+ ba.textwidget(parent=self._container,
+ position=(region_width * 0.57, 35),
+ color=(0, 1, 0),
+ scale=0.6,
+ size=(0, 0),
+ maxwidth=region_width * 0.5,
+ h_align='right',
+ v_align='center',
+ flatness=1.0,
+ text=ba.Lstr(
+ resource='gatherWindow.inviteAFriendText',
+ subs=[('${COUNT}', str(try_tickets))]))
+ ba.buttonwidget(
+ parent=self._container,
+ position=(region_width * 0.59, 10),
+ size=(230, 50),
+ color=(0.54, 0.42, 0.56),
+ textcolor=(0, 1, 0),
+ label=ba.Lstr(resource='gatherWindow.inviteFriendsText',
+ fallback_resource=(
+ 'gatherWindow.getFriendInviteCodeText')),
+ autoselect=True,
+ on_activate_call=ba.WeakCall(self._invite_to_try_press),
+ up_widget=tab_button)
+ return self._container
+
+ def _invite_to_try_press(self) -> None:
+ from bastd.ui.account import show_sign_in_prompt
+ from bastd.ui.appinvite import handle_app_invites_press
+ if _ba.get_account_state() != 'signed_in':
+ show_sign_in_prompt()
+ return
+ handle_app_invites_press()
diff --git a/assets/src/ba_data/python/bastd/ui/gather/manualtab.py b/assets/src/ba_data/python/bastd/ui/gather/manualtab.py
new file mode 100644
index 00000000..7ae3b1c8
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/ui/gather/manualtab.py
@@ -0,0 +1,833 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Defines the manual tab in the gather UI."""
+
+from __future__ import annotations
+
+import threading
+from typing import TYPE_CHECKING, cast
+
+from enum import Enum
+from dataclasses import dataclass
+from bastd.ui.gather import GatherTab
+
+import _ba
+import ba
+if TYPE_CHECKING:
+ from typing import Any, Optional, Dict, List, Tuple, Type, Union, Callable
+ from bastd.ui.gather import GatherWindow
+ from bastd.ui.confirm import ConfirmWindow
+
+
+def _safe_set_text(txt: Optional[ba.Widget],
+ val: Union[str, ba.Lstr],
+ success: bool = True) -> None:
+ if txt:
+ ba.textwidget(edit=txt,
+ text=val,
+ color=(0, 1, 0) if success else (1, 1, 0))
+
+
+class _HostLookupThread(threading.Thread):
+ """Thread to fetch an addr."""
+
+ def __init__(self, name: str, port: int,
+ call: Callable[[Optional[str], int], Any]):
+ super().__init__()
+ self._name = name
+ self._port = port
+ self._call = call
+
+ def run(self) -> None:
+ result: Optional[str]
+ try:
+ import socket
+ result = socket.gethostbyname(self._name)
+ except Exception:
+ result = None
+ ba.pushcall(lambda: self._call(result, self._port),
+ from_other_thread=True)
+
+
+class SubTabType(Enum):
+ """Available sub-tabs."""
+ JOIN_BY_ADDRESS = 'join_by_address'
+ FAVORITES = 'favorites'
+
+
+@dataclass
+class State:
+ """State saved/restored only while the app is running."""
+ sub_tab: SubTabType = SubTabType.JOIN_BY_ADDRESS
+
+
+class ManualGatherTab(GatherTab):
+ """The manual tab in the gather UI"""
+
+ def __init__(self, window: GatherWindow) -> None:
+ super().__init__(window)
+ self._check_button: Optional[ba.Widget] = None
+ self._doing_access_check: Optional[bool] = None
+ self._access_check_count: Optional[int] = None
+ self._sub_tab: SubTabType = SubTabType.JOIN_BY_ADDRESS
+ self._t_addr: Optional[ba.Widget] = None
+ self._t_accessible: Optional[ba.Widget] = None
+ self._t_accessible_extra: Optional[ba.Widget] = None
+ self._access_check_timer: Optional[ba.Timer] = None
+ self._checking_state_text: Optional[ba.Widget] = None
+ self._container: Optional[ba.Widget] = None
+ self._join_by_address_text: Optional[ba.Widget] = None
+ self._favorites_text: Optional[ba.Widget] = None
+ self._width: Optional[int] = None
+ self._height: Optional[int] = None
+ self._scroll_width: Optional[int] = None
+ self._scroll_height: Optional[int] = None
+ self._favorites_scroll_width: Optional[int] = None
+ self._favorites_connect_button: Optional[ba.Widget] = None
+ self._scrollwidget: Optional[ba.Widget] = None
+ self._columnwidget: Optional[ba.Widget] = None
+ self._favorite_selected: Optional[str] = None
+ self._favorite_rename_window: Optional[ba.Widget] = None
+ self._party_rename_text: Optional[ba.Widget] = None
+
+ def on_activate(
+ self,
+ parent_widget: ba.Widget,
+ tab_button: ba.Widget,
+ region_width: float,
+ region_height: float,
+ region_left: float,
+ region_bottom: float,
+ ) -> ba.Widget:
+
+ c_width = region_width
+ c_height = region_height - 20
+
+ self._container = ba.containerwidget(
+ parent=parent_widget,
+ position=(region_left,
+ region_bottom + (region_height - c_height) * 0.5),
+ size=(c_width, c_height),
+ background=False,
+ selection_loops_to_parent=True)
+ v = c_height - 30
+ self._join_by_address_text = ba.textwidget(
+ parent=self._container,
+ position=(c_width * 0.5 - 245, v - 13),
+ color=(0.6, 1.0, 0.6),
+ scale=1.3,
+ size=(200, 30),
+ maxwidth=250,
+ h_align='center',
+ v_align='center',
+ click_activate=True,
+ selectable=True,
+ autoselect=True,
+ on_activate_call=lambda: self._set_sub_tab(
+ SubTabType.JOIN_BY_ADDRESS,
+ region_width,
+ region_height,
+ playsound=True,
+ ),
+ text=ba.Lstr(resource='gatherWindow.manualJoinSectionText'))
+ self._favorites_text = ba.textwidget(
+ parent=self._container,
+ position=(c_width * 0.5 + 45, v - 13),
+ color=(0.6, 1.0, 0.6),
+ scale=1.3,
+ size=(200, 30),
+ maxwidth=250,
+ h_align='center',
+ v_align='center',
+ click_activate=True,
+ selectable=True,
+ autoselect=True,
+ on_activate_call=lambda: self._set_sub_tab(
+ SubTabType.FAVORITES,
+ region_width,
+ region_height,
+ playsound=True,
+ ),
+ text=ba.Lstr(resource='gatherWindow.favoritesText'))
+ ba.widget(edit=self._join_by_address_text, up_widget=tab_button)
+ ba.widget(edit=self._favorites_text,
+ left_widget=self._join_by_address_text,
+ up_widget=tab_button)
+ ba.widget(edit=tab_button, down_widget=self._favorites_text)
+ ba.widget(edit=self._join_by_address_text,
+ right_widget=self._favorites_text)
+ self._set_sub_tab(self._sub_tab, region_width, region_height)
+
+ return self._container
+
+ def save_state(self) -> None:
+ ba.app.ui.window_states[type(self)] = State(sub_tab=self._sub_tab)
+
+ def restore_state(self) -> None:
+ state = ba.app.ui.window_states.get(type(self))
+ if state is None:
+ state = State()
+ assert isinstance(state, State)
+ self._sub_tab = state.sub_tab
+
+ def _set_sub_tab(self,
+ value: SubTabType,
+ region_width: float,
+ region_height: float,
+ playsound: bool = False) -> None:
+ assert self._container
+ if playsound:
+ ba.playsound(ba.getsound('click01'))
+
+ self._sub_tab = value
+ active_color = (0.6, 1.0, 0.6)
+ inactive_color = (0.5, 0.4, 0.5)
+ ba.textwidget(edit=self._join_by_address_text,
+ color=active_color if value is SubTabType.JOIN_BY_ADDRESS
+ else inactive_color)
+ ba.textwidget(edit=self._favorites_text,
+ color=active_color
+ if value is SubTabType.FAVORITES else inactive_color)
+
+ # Clear anything existing in the old sub-tab.
+ for widget in self._container.get_children():
+ if widget and widget not in {
+ self._favorites_text, self._join_by_address_text
+ }:
+ widget.delete()
+
+ if value is SubTabType.JOIN_BY_ADDRESS:
+ self._build_join_by_address_tab(region_width, region_height)
+
+ if value is SubTabType.FAVORITES:
+ self._build_favorites_tab(region_height)
+
+ # The old manual tab
+ def _build_join_by_address_tab(self, region_width: float,
+ region_height: float) -> None:
+ c_width = region_width
+ c_height = region_height - 20
+ last_addr = ba.app.config.get('Last Manual Party Connect Address', '')
+ v = c_height - 70
+ v -= 70
+ ba.textwidget(parent=self._container,
+ position=(c_width * 0.5 - 260 - 50, v),
+ color=(0.6, 1.0, 0.6),
+ scale=1.0,
+ size=(0, 0),
+ maxwidth=130,
+ h_align='right',
+ v_align='center',
+ text=ba.Lstr(resource='gatherWindow.'
+ 'manualAddressText'))
+ txt = ba.textwidget(parent=self._container,
+ editable=True,
+ description=ba.Lstr(resource='gatherWindow.'
+ 'manualAddressText'),
+ position=(c_width * 0.5 - 240 - 50, v - 30),
+ text=last_addr,
+ autoselect=True,
+ v_align='center',
+ scale=1.0,
+ size=(420, 60))
+ ba.widget(edit=self._join_by_address_text, down_widget=txt)
+ ba.widget(edit=self._favorites_text, down_widget=txt)
+ ba.textwidget(parent=self._container,
+ position=(c_width * 0.5 - 260 + 490, v),
+ color=(0.6, 1.0, 0.6),
+ scale=1.0,
+ size=(0, 0),
+ maxwidth=80,
+ h_align='right',
+ v_align='center',
+ text=ba.Lstr(resource='gatherWindow.'
+ 'portText'))
+ txt2 = ba.textwidget(parent=self._container,
+ editable=True,
+ description=ba.Lstr(resource='gatherWindow.'
+ 'portText'),
+ text='43210',
+ autoselect=True,
+ max_chars=5,
+ position=(c_width * 0.5 - 240 + 490, v - 30),
+ v_align='center',
+ scale=1.0,
+ size=(170, 60))
+
+ v -= 110
+
+ btn = ba.buttonwidget(parent=self._container,
+ size=(300, 70),
+ label=ba.Lstr(resource='gatherWindow.'
+ 'manualConnectText'),
+ position=(c_width * 0.5 - 300, v),
+ autoselect=True,
+ on_activate_call=ba.Call(self._connect, txt,
+ txt2))
+ savebutton = ba.buttonwidget(
+ parent=self._container,
+ size=(300, 70),
+ label=ba.Lstr(resource='gatherWindow.favoritesSaveText'),
+ position=(c_width * 0.5 - 240 + 490 - 200, v),
+ autoselect=True,
+ on_activate_call=ba.Call(self._save_server, txt, txt2))
+ ba.widget(edit=btn, right_widget=savebutton)
+ ba.widget(edit=savebutton, left_widget=btn, up_widget=txt2)
+ ba.textwidget(edit=txt, on_return_press_call=btn.activate)
+ ba.textwidget(edit=txt2, on_return_press_call=btn.activate)
+ v -= 45
+
+ self._check_button = ba.textwidget(
+ parent=self._container,
+ size=(250, 60),
+ text=ba.Lstr(resource='gatherWindow.'
+ 'showMyAddressText'),
+ v_align='center',
+ h_align='center',
+ click_activate=True,
+ position=(c_width * 0.5 - 125, v - 30),
+ autoselect=True,
+ color=(0.5, 0.9, 0.5),
+ scale=0.8,
+ selectable=True,
+ on_activate_call=ba.Call(self._on_show_my_address_button_press, v,
+ self._container, c_width))
+ ba.widget(edit=self._check_button, up_widget=btn)
+
+ # Tab containing saved favorite addresses
+ def _build_favorites_tab(self, region_height: float) -> None:
+
+ c_height = region_height - 20
+ v = c_height - 35 - 25 - 30
+
+ 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
+ 670 if uiscale is ba.UIScale.MEDIUM else 800)
+
+ self._scroll_width = self._width - 130 + 2 * x_inset
+ self._scroll_height = self._height - 180
+ x_inset = 100 if uiscale is ba.UIScale.SMALL else 0
+
+ c_height = self._scroll_height - 20
+ sub_scroll_height = c_height - 63
+ self._favorites_scroll_width = sub_scroll_width = (
+ 680 if uiscale is ba.UIScale.SMALL else 640)
+
+ v = c_height - 30
+
+ 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)
+
+ btnv = (c_height - (48 if uiscale is ba.UIScale.SMALL else
+ 45 if uiscale is ba.UIScale.MEDIUM else 40) -
+ b_height)
+
+ self._favorites_connect_button = btn1 = ba.buttonwidget(
+ parent=self._container,
+ size=(b_width, b_height),
+ position=(40 if uiscale is ba.UIScale.SMALL else 40, btnv),
+ button_type='square',
+ color=(0.6, 0.53, 0.63),
+ textcolor=(0.75, 0.7, 0.8),
+ on_activate_call=self._on_favorites_connect_press,
+ text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2,
+ label=ba.Lstr(resource='gatherWindow.manualConnectText'),
+ autoselect=True)
+ 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
+ ba.buttonwidget(parent=self._container,
+ size=(b_width, b_height),
+ position=(40 if uiscale is ba.UIScale.SMALL else 40,
+ btnv),
+ button_type='square',
+ color=(0.6, 0.53, 0.63),
+ textcolor=(0.75, 0.7, 0.8),
+ on_activate_call=self._on_favorites_rename_press,
+ text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2,
+ label=ba.Lstr(resource='renameText'),
+ autoselect=True)
+ btnv -= b_height + b_space_extra
+ ba.buttonwidget(parent=self._container,
+ size=(b_width, b_height),
+ position=(40 if uiscale is ba.UIScale.SMALL else 40,
+ btnv),
+ button_type='square',
+ color=(0.6, 0.53, 0.63),
+ textcolor=(0.75, 0.7, 0.8),
+ on_activate_call=self._on_favorite_delete_press,
+ text_scale=1.0 if uiscale is ba.UIScale.SMALL else 1.2,
+ label=ba.Lstr(resource='deleteText'),
+ autoselect=True)
+
+ v -= sub_scroll_height + 23
+ self._scrollwidget = scrlw = ba.scrollwidget(
+ parent=self._container,
+ position=(190 if uiscale is ba.UIScale.SMALL else 225, v),
+ size=(sub_scroll_width, sub_scroll_height),
+ claims_left_right=True)
+ ba.widget(edit=self._favorites_connect_button,
+ right_widget=self._scrollwidget)
+ self._columnwidget = ba.columnwidget(parent=scrlw,
+ left_border=10,
+ border=2,
+ margin=0,
+ claims_left_right=True)
+
+ self._favorite_selected = None
+ self._refresh_favorites()
+
+ def _no_favorite_selected_error(self) -> None:
+ ba.screenmessage(ba.Lstr(resource='nothingIsSelectedErrorText'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+
+ def _on_favorites_connect_press(self) -> None:
+ if self._favorite_selected is None:
+ self._no_favorite_selected_error()
+
+ else:
+ config = ba.app.config['Saved Servers'][self._favorite_selected]
+ _HostLookupThread(name=config['addr'],
+ port=config['port'],
+ call=ba.WeakCall(
+ self._host_lookup_result)).start()
+
+ def _on_favorites_rename_press(self) -> None:
+ if self._favorite_selected is None:
+ self._no_favorite_selected_error()
+ return
+
+ c_width = 600
+ c_height = 250
+ uiscale = ba.app.ui.uiscale
+ self._favorite_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),
+ size=(c_width, c_height),
+ transition='in_scale')
+
+ ba.textwidget(parent=cnt,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ text='Enter Name of Party',
+ maxwidth=c_width * 0.8,
+ position=(c_width * 0.5, c_height - 60))
+ self._party_rename_text = txt = ba.textwidget(
+ parent=cnt,
+ size=(c_width * 0.8, 40),
+ h_align='left',
+ v_align='center',
+ text=ba.app.config['Saved Servers'][
+ self._favorite_selected]['name'],
+ editable=True,
+ description='Server name text',
+ position=(c_width * 0.1, c_height - 140),
+ autoselect=True,
+ maxwidth=c_width * 0.7,
+ max_chars=200)
+ cbtn = ba.buttonwidget(
+ parent=cnt,
+ label=ba.Lstr(resource='cancelText'),
+ on_activate_call=ba.Call(
+ lambda c: ba.containerwidget(edit=c, transition='out_scale'),
+ cnt),
+ size=(180, 60),
+ position=(30, 30),
+ autoselect=True)
+ okb = ba.buttonwidget(parent=cnt,
+ label='Rename',
+ size=(180, 60),
+ position=(c_width - 230, 30),
+ on_activate_call=ba.Call(
+ self._rename_saved_party),
+ autoselect=True)
+ ba.widget(edit=cbtn, right_widget=okb)
+ ba.widget(edit=okb, left_widget=cbtn)
+ ba.textwidget(edit=txt, on_return_press_call=okb.activate)
+ ba.containerwidget(edit=cnt, cancel_button=cbtn, start_button=okb)
+
+ def _rename_saved_party(self) -> None:
+
+ server = self._favorite_selected
+ if self._favorite_selected is None:
+ self._no_favorite_selected_error()
+ return
+ if not self._party_rename_text:
+ return
+ new_name_raw = cast(str, ba.textwidget(query=self._party_rename_text))
+ ba.app.config['Saved Servers'][server]['name'] = new_name_raw
+ ba.app.config.commit()
+ ba.playsound(ba.getsound('gunCocking'))
+ self._refresh_favorites()
+
+ ba.containerwidget(edit=self._favorite_rename_window,
+ transition='out_scale')
+
+ def _on_favorite_delete_press(self) -> None:
+ from bastd.ui import confirm
+ if self._favorite_selected is None:
+ self._no_favorite_selected_error()
+ return
+ confirm.ConfirmWindow(
+ ba.Lstr(resource='gameListWindow.deleteConfirmText',
+ subs=[('${LIST}', ba.app.config['Saved Servers'][
+ self._favorite_selected]['name'])]),
+ self._delete_saved_party, 450, 150)
+
+ def _delete_saved_party(self) -> None:
+ if self._favorite_selected is None:
+ self._no_favorite_selected_error()
+ return
+ config = ba.app.config['Saved Servers']
+ del config[self._favorite_selected]
+ self._favorite_selected = None
+ ba.app.config.commit()
+ ba.playsound(ba.getsound('shieldDown'))
+ self._refresh_favorites()
+
+ def _on_favorite_select(self, server: str) -> None:
+ self._favorite_selected = server
+
+ def _refresh_favorites(self) -> None:
+ assert self._columnwidget is not None
+ for child in self._columnwidget.get_children():
+ child.delete()
+ t_scale = 1.6
+
+ config = ba.app.config
+ if 'Saved Servers' in config:
+ servers = config['Saved Servers']
+
+ else:
+ servers = []
+
+ assert self._favorites_scroll_width is not None
+ assert self._favorites_connect_button is not None
+ for i, server in enumerate(servers):
+ txt = ba.textwidget(
+ parent=self._columnwidget,
+ size=(self._favorites_scroll_width / t_scale, 30),
+ selectable=True,
+ color=(1.0, 1, 0.4),
+ always_highlight=True,
+ on_select_call=ba.Call(self._on_favorite_select, server),
+ on_activate_call=self._favorites_connect_button.activate,
+ text=(config['Saved Servers'][server]['name']
+ if config['Saved Servers'][server]['name'] != '' else
+ config['Saved Servers'][server]['addr'] + ' ' +
+ str(config['Saved Servers'][server]['port'])),
+ h_align='left',
+ v_align='center',
+ corner_scale=t_scale,
+ maxwidth=(self._favorites_scroll_width / t_scale) * 0.93)
+ if i == 0:
+ ba.widget(edit=txt, up_widget=self._favorites_text)
+ ba.widget(edit=txt,
+ left_widget=self._favorites_connect_button,
+ right_widget=txt)
+
+ # If there's no servers, allow selecting out of the scroll area
+ ba.containerwidget(edit=self._scrollwidget,
+ claims_left_right=bool(servers),
+ claims_up_down=bool(servers))
+ ba.widget(edit=self._scrollwidget,
+ up_widget=self._favorites_text,
+ left_widget=self._favorites_connect_button)
+
+ def on_deactivate(self) -> None:
+ self._access_check_timer = None
+
+ def _connect(self, textwidget: ba.Widget,
+ port_textwidget: ba.Widget) -> None:
+ addr = cast(str, ba.textwidget(query=textwidget))
+ if addr == '':
+ ba.screenmessage(
+ ba.Lstr(resource='internal.invalidAddressErrorText'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ return
+ 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'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ return
+
+ _HostLookupThread(name=addr,
+ port=port,
+ call=ba.WeakCall(self._host_lookup_result)).start()
+
+ def _save_server(self, textwidget: ba.Widget,
+ port_textwidget: ba.Widget) -> None:
+ addr = cast(str, ba.textwidget(query=textwidget))
+ if addr == '':
+ ba.screenmessage(
+ ba.Lstr(resource='internal.invalidAddressErrorText'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ return
+ 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'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ return
+ config = ba.app.config
+
+ if addr:
+ if not isinstance(config.get('Saved Servers'), dict):
+ config['Saved Servers'] = {}
+ config['Saved Servers'][f'{addr}@{port}'] = {
+ 'addr': addr,
+ 'port': port,
+ 'name': addr
+ }
+ config.commit()
+ ba.playsound(ba.getsound('gunCocking'))
+ else:
+ ba.screenmessage('Invalid Address', color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+
+ def _host_lookup_result(self, resolved_address: Optional[str],
+ port: int) -> None:
+ if resolved_address is None:
+ ba.screenmessage(
+ ba.Lstr(resource='internal.unableToResolveHostText'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ else:
+ # Store for later.
+ config = ba.app.config
+ config['Last Manual Party Connect Address'] = resolved_address
+ config.commit()
+ _ba.connect_to_party(resolved_address, port=port)
+
+ def _run_addr_fetch(self) -> None:
+ try:
+ # FIXME: Update this to work with IPv6.
+ import socket
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.connect(('8.8.8.8', 80))
+ val = sock.getsockname()[0]
+ sock.close()
+ ba.pushcall(
+ ba.Call(
+ _safe_set_text,
+ self._checking_state_text,
+ val,
+ ),
+ from_other_thread=True,
+ )
+ except Exception as exc:
+ err_str = str(exc)
+
+ # FIXME: Should look at exception types here,
+ # not strings.
+ if 'Network is unreachable' in err_str:
+ ba.pushcall(ba.Call(
+ _safe_set_text, self._checking_state_text,
+ ba.Lstr(resource='gatherWindow.'
+ 'noConnectionText'), False),
+ from_other_thread=True)
+ else:
+ ba.pushcall(ba.Call(
+ _safe_set_text, self._checking_state_text,
+ ba.Lstr(resource='gatherWindow.'
+ 'addressFetchErrorText'), False),
+ from_other_thread=True)
+ ba.pushcall(ba.Call(ba.print_error,
+ 'error in AddrFetchThread: ' + str(exc)),
+ from_other_thread=True)
+
+ def _on_show_my_address_button_press(self, v2: float,
+ container: Optional[ba.Widget],
+ c_width: float) -> None:
+ if not container:
+ return
+
+ tscl = 0.85
+ tspc = 25
+
+ ba.playsound(ba.getsound('swish'))
+ ba.textwidget(parent=container,
+ position=(c_width * 0.5 - 10, v2),
+ color=(0.6, 1.0, 0.6),
+ scale=tscl,
+ size=(0, 0),
+ maxwidth=c_width * 0.45,
+ flatness=1.0,
+ h_align='right',
+ v_align='center',
+ text=ba.Lstr(resource='gatherWindow.'
+ 'manualYourLocalAddressText'))
+ self._checking_state_text = ba.textwidget(
+ parent=container,
+ position=(c_width * 0.5, v2),
+ color=(0.5, 0.5, 0.5),
+ scale=tscl,
+ size=(0, 0),
+ maxwidth=c_width * 0.45,
+ flatness=1.0,
+ h_align='left',
+ v_align='center',
+ text=ba.Lstr(resource='gatherWindow.'
+ 'checkingText'))
+
+ threading.Thread(target=self._run_addr_fetch).start()
+
+ v2 -= tspc
+ ba.textwidget(parent=container,
+ position=(c_width * 0.5 - 10, v2),
+ color=(0.6, 1.0, 0.6),
+ scale=tscl,
+ size=(0, 0),
+ maxwidth=c_width * 0.45,
+ flatness=1.0,
+ h_align='right',
+ v_align='center',
+ text=ba.Lstr(resource='gatherWindow.'
+ 'manualYourAddressFromInternetText'))
+
+ t_addr = ba.textwidget(parent=container,
+ position=(c_width * 0.5, v2),
+ color=(0.5, 0.5, 0.5),
+ scale=tscl,
+ size=(0, 0),
+ maxwidth=c_width * 0.45,
+ h_align='left',
+ v_align='center',
+ flatness=1.0,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'checkingText'))
+ v2 -= tspc
+ ba.textwidget(parent=container,
+ position=(c_width * 0.5 - 10, v2),
+ color=(0.6, 1.0, 0.6),
+ scale=tscl,
+ size=(0, 0),
+ maxwidth=c_width * 0.45,
+ flatness=1.0,
+ h_align='right',
+ v_align='center',
+ text=ba.Lstr(resource='gatherWindow.'
+ 'manualJoinableFromInternetText'))
+
+ t_accessible = ba.textwidget(parent=container,
+ position=(c_width * 0.5, v2),
+ color=(0.5, 0.5, 0.5),
+ scale=tscl,
+ size=(0, 0),
+ maxwidth=c_width * 0.45,
+ flatness=1.0,
+ h_align='left',
+ v_align='center',
+ text=ba.Lstr(resource='gatherWindow.'
+ 'checkingText'))
+ v2 -= 28
+ t_accessible_extra = ba.textwidget(parent=container,
+ position=(c_width * 0.5, v2),
+ color=(1, 0.5, 0.2),
+ scale=0.7,
+ size=(0, 0),
+ maxwidth=c_width * 0.9,
+ flatness=1.0,
+ h_align='center',
+ v_align='center',
+ text='')
+
+ self._doing_access_check = False
+ self._access_check_count = 0 # Cap our refreshes eventually.
+ self._access_check_timer = ba.Timer(
+ 10.0,
+ ba.WeakCall(self._access_check_update, t_addr, t_accessible,
+ t_accessible_extra),
+ repeat=True,
+ timetype=ba.TimeType.REAL)
+
+ # Kick initial off.
+ self._access_check_update(t_addr, t_accessible, t_accessible_extra)
+ if self._check_button:
+ self._check_button.delete()
+
+ def _access_check_update(self, t_addr: ba.Widget, t_accessible: ba.Widget,
+ t_accessible_extra: ba.Widget) -> None:
+ 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
+ assert self._access_check_count is not None
+ if not self._doing_access_check and self._access_check_count < 100:
+ self._doing_access_check = True
+ self._access_check_count += 1
+ self._t_addr = t_addr
+ self._t_accessible = t_accessible
+ self._t_accessible_extra = t_accessible_extra
+ 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
+ t_accessible = self._t_accessible
+ t_accessible_extra = self._t_accessible_extra
+ self._doing_access_check = False
+ color_bad = (1, 1, 0)
+ color_good = (0, 1, 0)
+ if data is None or 'address' not in data or 'accessible' not in data:
+ if t_addr:
+ ba.textwidget(edit=t_addr,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'noConnectionText'),
+ color=color_bad)
+ if t_accessible:
+ ba.textwidget(edit=t_accessible,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'noConnectionText'),
+ color=color_bad)
+ if t_accessible_extra:
+ ba.textwidget(edit=t_accessible_extra,
+ text='',
+ color=color_bad)
+ return
+ if t_addr:
+ ba.textwidget(edit=t_addr, text=data['address'], color=color_good)
+ if t_accessible:
+ if data['accessible']:
+ ba.textwidget(edit=t_accessible,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'manualJoinableYesText'),
+ color=color_good)
+ if t_accessible_extra:
+ ba.textwidget(edit=t_accessible_extra,
+ text='',
+ color=color_good)
+ else:
+ ba.textwidget(
+ edit=t_accessible,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'manualJoinableNoWithAsteriskText'),
+ color=color_bad,
+ )
+ if t_accessible_extra:
+ ba.textwidget(
+ edit=t_accessible_extra,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'manualRouterForwardingText',
+ subs=[('${PORT}',
+ str(_ba.get_game_port()))]),
+ color=color_bad,
+ )
diff --git a/assets/src/ba_data/python/bastd/ui/gather/nearbytab.py b/assets/src/ba_data/python/bastd/ui/gather/nearbytab.py
new file mode 100644
index 00000000..19fe1c53
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/ui/gather/nearbytab.py
@@ -0,0 +1,146 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Defines the nearby tab in the gather UI."""
+
+from __future__ import annotations
+
+import weakref
+from typing import TYPE_CHECKING
+
+import ba
+import _ba
+from bastd.ui.gather import GatherTab
+
+if TYPE_CHECKING:
+ from typing import Optional, Dict, Any
+ from bastd.ui.gather import GatherWindow
+
+
+class NetScanner:
+ """Class for scanning for games on the lan."""
+
+ def __init__(self, tab: GatherTab, scrollwidget: ba.Widget,
+ tab_button: ba.Widget, width: float):
+ self._tab = weakref.ref(tab)
+ self._scrollwidget = scrollwidget
+ self._tab_button = tab_button
+ self._columnwidget = ba.columnwidget(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
+
+ self._update_timer = ba.Timer(1.0,
+ ba.WeakCall(self.update),
+ timetype=ba.TimeType.REAL,
+ repeat=True)
+ # Go ahead and run a few *almost* immediately so we don't
+ # have to wait a second.
+ self.update()
+ ba.timer(0.25, ba.WeakCall(self.update), timetype=ba.TimeType.REAL)
+
+ def __del__(self) -> None:
+ _ba.end_host_scanning()
+
+ def _on_select(self, host: Dict[str, Any]) -> None:
+ self._last_selected_host = host
+
+ def _on_activate(self, host: Dict[str, Any]) -> None:
+ _ba.connect_to_party(host['address'])
+
+ def update(self) -> None:
+ """(internal)"""
+
+ # In case our UI was killed from under us.
+ if not self._columnwidget:
+ print(f'ERROR: NetScanner running without UI at time'
+ f' {ba.time(timetype=ba.TimeType.REAL)}.')
+ return
+
+ t_scale = 1.6
+ for child in self._columnwidget.get_children():
+ child.delete()
+
+ # Grab this now this since adding widgets will change it.
+ last_selected_host = self._last_selected_host
+ hosts = _ba.host_scan_cycle()
+ for i, host in enumerate(hosts):
+ txt3 = ba.textwidget(parent=self._columnwidget,
+ size=(self._width / t_scale, 30),
+ selectable=True,
+ color=(1, 1, 1),
+ on_select_call=ba.Call(self._on_select, host),
+ on_activate_call=ba.Call(
+ self._on_activate, host),
+ click_activate=True,
+ text=host['display_string'],
+ h_align='left',
+ v_align='center',
+ corner_scale=t_scale,
+ maxwidth=(self._width / t_scale) * 0.93)
+ if host == last_selected_host:
+ ba.containerwidget(edit=self._columnwidget,
+ selected_child=txt3,
+ visible_child=txt3)
+ if i == 0:
+ ba.widget(edit=txt3, up_widget=self._tab_button)
+
+
+class NearbyGatherTab(GatherTab):
+ """The nearby tab in the gather UI"""
+
+ def __init__(self, window: GatherWindow) -> None:
+ super().__init__(window)
+ self._net_scanner: Optional[NetScanner] = None
+ self._container: Optional[ba.Widget] = None
+
+ def on_activate(
+ self,
+ parent_widget: ba.Widget,
+ tab_button: ba.Widget,
+ region_width: float,
+ region_height: float,
+ region_left: float,
+ region_bottom: float,
+ ) -> ba.Widget:
+ c_width = region_width
+ c_height = region_height - 20
+ sub_scroll_height = c_height - 85
+ sub_scroll_width = 650
+ self._container = ba.containerwidget(
+ parent=parent_widget,
+ position=(region_left,
+ region_bottom + (region_height - c_height) * 0.5),
+ size=(c_width, c_height),
+ background=False,
+ selection_loops_to_parent=True)
+ v = c_height - 30
+ ba.textwidget(parent=self._container,
+ position=(c_width * 0.5, v - 3),
+ 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='gatherWindow.'
+ 'localNetworkDescriptionText'))
+ v -= 15
+ v -= sub_scroll_height + 23
+ scrollw = ba.scrollwidget(parent=self._container,
+ position=((region_width - sub_scroll_width) *
+ 0.5, v),
+ size=(sub_scroll_width, sub_scroll_height))
+
+ self._net_scanner = NetScanner(self,
+ scrollw,
+ tab_button,
+ width=sub_scroll_width)
+
+ ba.widget(edit=scrollw, autoselect=True, up_widget=tab_button)
+ return self._container
+
+ def on_deactivate(self) -> None:
+ self._net_scanner = None
diff --git a/assets/src/ba_data/python/bastd/ui/gather/privatetab.py b/assets/src/ba_data/python/bastd/ui/gather/privatetab.py
new file mode 100644
index 00000000..b14575dd
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/ui/gather/privatetab.py
@@ -0,0 +1,870 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Defines the Private tab in the gather UI."""
+
+from __future__ import annotations
+
+import os
+import copy
+import time
+from enum import Enum
+from dataclasses import dataclass, asdict
+from typing import TYPE_CHECKING, cast
+
+import ba
+import _ba
+from efro.dataclasses import dataclass_from_dict
+from bastd.ui.gather import GatherTab
+from bastd.ui import getcurrency
+
+if TYPE_CHECKING:
+ from typing import Optional, Dict, Any, List, Type
+ from bastd.ui.gather import GatherWindow
+
+# Print a bit of info about queries, etc.
+DEBUG_SERVER_COMMUNICATION = os.environ.get('BA_DEBUG_PPTABCOM') == '1'
+
+
+class SubTabType(Enum):
+ """Available sub-tabs."""
+ JOIN = 'join'
+ HOST = 'host'
+
+
+@dataclass
+class State:
+ """Our core state that persists while the app is running."""
+ sub_tab: SubTabType = SubTabType.JOIN
+
+
+@dataclass
+class ConnectResult:
+ """Info about a server we get back when connecting."""
+ error: Optional[str] = None
+ addr: Optional[str] = None
+ port: Optional[int] = None
+
+
+@dataclass
+class HostingState:
+ """Our combined state of whether we're hosting, whether we can, etc."""
+ unavailable_error: Optional[str] = None
+ party_code: Optional[str] = None
+ able_to_host: bool = False
+ tickets_to_host_now: int = 0
+ minutes_until_free_host: Optional[float] = None
+ free_host_minutes_remaining: Optional[float] = None
+
+
+@dataclass
+class HostingConfig:
+ """Config we provide when hosting."""
+ session_type: str = 'ffa'
+ playlist_name: str = 'Unknown'
+ randomize: bool = False
+ tutorial: bool = False
+ custom_team_names: Optional[List[str]] = None
+ custom_team_colors: Optional[List[List[float]]] = None
+ playlist: Optional[List[Dict[str, Any]]] = None
+
+
+class PrivateGatherTab(GatherTab):
+ """The private tab in the gather UI"""
+
+ def __init__(self, window: GatherWindow) -> None:
+ super().__init__(window)
+ self._container: Optional[ba.Widget] = None
+ self._state: State = State()
+ self._hostingstate = HostingState()
+ self._join_sub_tab_text: Optional[ba.Widget] = None
+ self._host_sub_tab_text: Optional[ba.Widget] = None
+ self._update_timer: Optional[ba.Timer] = None
+ self._join_party_code_text: Optional[ba.Widget] = None
+ self._c_width: float = 0.0
+ self._c_height: float = 0.0
+ self._last_hosting_state_query_time: Optional[float] = None
+ self._waiting_for_initial_state = True
+ self._waiting_for_start_stop_response = True
+ self._host_playlist_button: Optional[ba.Widget] = None
+ self._host_copy_button: Optional[ba.Widget] = None
+ self._host_connect_button: Optional[ba.Widget] = None
+ self._host_start_stop_button: Optional[ba.Widget] = None
+ self._get_tickets_button: Optional[ba.Widget] = None
+ self._ticket_count_text: Optional[ba.Widget] = None
+ self._showing_not_signed_in_screen = False
+ self._create_time = time.time()
+ self._last_action_send_time: Optional[float] = None
+ self._connect_press_time: Optional[float] = None
+ try:
+ self._hostingconfig = self._build_hosting_config()
+ except Exception:
+ ba.print_exception('Error building hosting config')
+ self._hostingconfig = HostingConfig()
+
+ def on_activate(
+ self,
+ parent_widget: ba.Widget,
+ tab_button: ba.Widget,
+ region_width: float,
+ region_height: float,
+ region_left: float,
+ region_bottom: float,
+ ) -> ba.Widget:
+ self._c_width = region_width
+ self._c_height = region_height - 20
+ self._container = ba.containerwidget(
+ parent=parent_widget,
+ position=(region_left,
+ region_bottom + (region_height - self._c_height) * 0.5),
+ size=(self._c_width, self._c_height),
+ background=False,
+ selection_loops_to_parent=True)
+ v = self._c_height - 30.0
+ self._join_sub_tab_text = ba.textwidget(
+ parent=self._container,
+ position=(self._c_width * 0.5 - 245, v - 13),
+ color=(0.6, 1.0, 0.6),
+ scale=1.3,
+ size=(200, 30),
+ maxwidth=250,
+ h_align='left',
+ v_align='center',
+ click_activate=True,
+ selectable=True,
+ autoselect=True,
+ on_activate_call=lambda: self._set_sub_tab(
+ SubTabType.JOIN,
+ playsound=True,
+ ),
+ text=ba.Lstr(resource='gatherWindow.privatePartyJoinText'))
+ self._host_sub_tab_text = ba.textwidget(
+ parent=self._container,
+ position=(self._c_width * 0.5 + 45, v - 13),
+ color=(0.6, 1.0, 0.6),
+ scale=1.3,
+ size=(200, 30),
+ maxwidth=250,
+ h_align='left',
+ v_align='center',
+ click_activate=True,
+ selectable=True,
+ autoselect=True,
+ on_activate_call=lambda: self._set_sub_tab(
+ SubTabType.HOST,
+ playsound=True,
+ ),
+ text=ba.Lstr(resource='gatherWindow.privatePartyHostText'))
+ ba.widget(edit=self._join_sub_tab_text, up_widget=tab_button)
+ ba.widget(edit=self._host_sub_tab_text,
+ left_widget=self._join_sub_tab_text,
+ up_widget=tab_button)
+ ba.widget(edit=self._join_sub_tab_text,
+ right_widget=self._host_sub_tab_text)
+
+ self._update_timer = ba.Timer(1.0,
+ ba.WeakCall(self._update),
+ repeat=True,
+ timetype=ba.TimeType.REAL)
+
+ # Prevent taking any action until we've updated our state.
+ self._waiting_for_initial_state = True
+
+ # This will get a state query sent out immediately.
+ self._last_action_send_time = None # Ensure we don't ignore response.
+ self._last_hosting_state_query_time = None
+ self._update()
+
+ self._set_sub_tab(self._state.sub_tab)
+
+ return self._container
+
+ def _build_hosting_config(self) -> HostingConfig:
+ from bastd.ui.playlist import PlaylistTypeVars
+ from ba.internal import filter_playlist
+ hcfg = HostingConfig()
+ cfg = ba.app.config
+ sessiontypestr = cfg.get('Private Party Host Session Type', 'ffa')
+ if not isinstance(sessiontypestr, str):
+ raise RuntimeError(f'Invalid sessiontype {sessiontypestr}')
+ hcfg.session_type = sessiontypestr
+
+ sessiontype: Type[ba.Session]
+ if hcfg.session_type == 'ffa':
+ sessiontype = ba.FreeForAllSession
+ elif hcfg.session_type == 'teams':
+ sessiontype = ba.DualTeamSession
+ else:
+ raise RuntimeError('fInvalid sessiontype: {hcfg.session_type}')
+ pvars = PlaylistTypeVars(sessiontype)
+
+ playlist_name = ba.app.config.get(
+ f'{pvars.config_name} Playlist Selection')
+ if not isinstance(playlist_name, str):
+ playlist_name = '__default__'
+ hcfg.playlist_name = (pvars.default_list_name.evaluate()
+ if playlist_name == '__default__' else
+ playlist_name)
+
+ if playlist_name == '__default__':
+ playlist = pvars.get_default_list_call()
+ else:
+ playlist = cfg[f'{pvars.config_name} Playlists'][playlist_name]
+ hcfg.playlist = filter_playlist(playlist, sessiontype)
+
+ randomize = cfg.get(f'{pvars.config_name} Playlist Randomize')
+ if not isinstance(randomize, bool):
+ randomize = False
+ hcfg.randomize = randomize
+
+ tutorial = cfg.get('Show Tutorial')
+ if not isinstance(tutorial, bool):
+ tutorial = False
+ hcfg.tutorial = tutorial
+
+ if hcfg.session_type == 'teams':
+ hcfg.custom_team_names = copy.copy(cfg.get('Custom Team Names'))
+ hcfg.custom_team_colors = copy.copy(cfg.get('Custom Team Colors'))
+
+ return hcfg
+
+ def on_deactivate(self) -> None:
+ self._update_timer = None
+
+ def _update_currency_ui(self) -> None:
+ # Keep currency count up to date if applicable.
+ try:
+ t_str = str(_ba.get_account_ticket_count())
+ except Exception:
+ t_str = '?'
+ if self._get_tickets_button:
+ ba.buttonwidget(edit=self._get_tickets_button,
+ label=ba.charstr(ba.SpecialChar.TICKET) + t_str)
+ if self._ticket_count_text:
+ ba.textwidget(edit=self._ticket_count_text,
+ text=ba.charstr(ba.SpecialChar.TICKET) + t_str)
+
+ def _update(self) -> None:
+ """Periodic updating."""
+
+ now = ba.time(ba.TimeType.REAL)
+
+ self._update_currency_ui()
+
+ if self._state.sub_tab is SubTabType.HOST:
+
+ # If we're not signed in, just refresh to show that.
+ if (_ba.get_account_state() != 'signed_in'
+ and self._showing_not_signed_in_screen):
+ self._refresh_sub_tab()
+ else:
+
+ # Query an updated state periodically.
+ if (self._last_hosting_state_query_time is None
+ or now - self._last_hosting_state_query_time > 15.0):
+ self._debug_server_comm('querying private party state')
+ if _ba.get_account_state() == 'signed_in':
+ _ba.add_transaction(
+ {'type': 'PRIVATE_PARTY_QUERY'},
+ callback=ba.WeakCall(
+ self._hosting_state_idle_response),
+ )
+ _ba.run_transactions()
+ else:
+ self._hosting_state_idle_response(None)
+ self._last_hosting_state_query_time = now
+
+ def _hosting_state_idle_response(self,
+ result: Optional[Dict[str, Any]]) -> None:
+
+ # This simply passes through to our standard response handler.
+ # The one exception is if we've recently sent an action to the
+ # server (start/stop hosting/etc.) In that case we want to ignore
+ # idle background updates and wait for the response to our action.
+ # (this keeps the button showing 'one moment...' until the change
+ # takes effect, etc.)
+ if (self._last_action_send_time is not None
+ and time.time() - self._last_action_send_time < 5.0):
+ self._debug_server_comm('ignoring private party state response'
+ ' due to recent action')
+ return
+ self._hosting_state_response(result)
+
+ def _hosting_state_response(self, result: Optional[Dict[str,
+ Any]]) -> None:
+
+ # Its possible for this to come back to us after our UI is dead;
+ # ignore in that case.
+ if not self._container:
+ return
+
+ state: Optional[HostingState] = None
+ if result is not None:
+ self._debug_server_comm('got private party state response')
+ try:
+ state = dataclass_from_dict(HostingState, result)
+ except Exception:
+ pass
+ else:
+ self._debug_server_comm('private party state response errored')
+
+ # Hmm I guess let's just ignore failed responses?...
+ # Or should we show some sort of error state to the user?...
+ if result is None or state is None:
+ return
+
+ self._waiting_for_initial_state = False
+ self._waiting_for_start_stop_response = False
+ self._hostingstate = state
+ self._refresh_sub_tab()
+
+ def _set_sub_tab(self, value: SubTabType, playsound: bool = False) -> None:
+ assert self._container
+ if playsound:
+ ba.playsound(ba.getsound('click01'))
+
+ # If switching from join to host, do a fresh state query.
+ if self._state.sub_tab is SubTabType.JOIN and value is SubTabType.HOST:
+ # Prevent taking any action until we've gotten a fresh state.
+ self._waiting_for_initial_state = True
+
+ # This will get a state query sent out immediately.
+ self._last_hosting_state_query_time = None
+ self._last_action_send_time = None # So we don't ignore response.
+ self._update()
+
+ self._state.sub_tab = value
+ active_color = (0.6, 1.0, 0.6)
+ inactive_color = (0.5, 0.4, 0.5)
+ ba.textwidget(
+ edit=self._join_sub_tab_text,
+ color=active_color if value is SubTabType.JOIN else inactive_color)
+ ba.textwidget(
+ edit=self._host_sub_tab_text,
+ color=active_color if value is SubTabType.HOST else inactive_color)
+
+ self._refresh_sub_tab()
+
+ # Kick off an update to get any needed messages sent/etc.
+ ba.pushcall(self._update)
+
+ def _selwidgets(self) -> List[Optional[ba.Widget]]:
+ """An indexed list of widgets we can use for saving/restoring sel."""
+ return [
+ self._host_playlist_button, self._host_copy_button,
+ self._host_connect_button, self._host_start_stop_button,
+ self._get_tickets_button
+ ]
+
+ def _refresh_sub_tab(self) -> None:
+ assert self._container
+
+ # Store an index for our current selection so we can
+ # reselect the equivalent recreated widget if possible.
+ selindex: Optional[int] = None
+ selchild = self._container.get_selected_child()
+ if selchild is not None:
+ try:
+ selindex = self._selwidgets().index(selchild)
+ except ValueError:
+ pass
+
+ # Clear anything existing in the old sub-tab.
+ for widget in self._container.get_children():
+ if widget and widget not in {
+ self._host_sub_tab_text,
+ self._join_sub_tab_text,
+ }:
+ widget.delete()
+
+ if self._state.sub_tab is SubTabType.JOIN:
+ self._build_join_tab()
+ elif self._state.sub_tab is SubTabType.HOST:
+ self._build_host_tab()
+ else:
+ raise RuntimeError('Invalid state.')
+
+ # Select the new equivalent widget if there is one.
+ if selindex is not None:
+ selwidget = self._selwidgets()[selindex]
+ if selwidget:
+ ba.containerwidget(edit=self._container,
+ selected_child=selwidget)
+
+ def _build_join_tab(self) -> None:
+
+ ba.textwidget(parent=self._container,
+ position=(self._c_width * 0.5, self._c_height - 140),
+ color=(0.5, 0.46, 0.5),
+ scale=1.5,
+ size=(0, 0),
+ maxwidth=250,
+ h_align='center',
+ v_align='center',
+ text=ba.Lstr(resource='gatherWindow.partyCodeText'))
+
+ self._join_party_code_text = ba.textwidget(
+ parent=self._container,
+ position=(self._c_width * 0.5 - 150, self._c_height - 250),
+ flatness=1.0,
+ scale=1.5,
+ size=(300, 50),
+ editable=True,
+ description=ba.Lstr(resource='gatherWindow.partyCodeText'),
+ autoselect=True,
+ maxwidth=250,
+ h_align='left',
+ v_align='center',
+ text='')
+ btn = ba.buttonwidget(parent=self._container,
+ size=(300, 70),
+ label=ba.Lstr(resource='gatherWindow.'
+ 'manualConnectText'),
+ position=(self._c_width * 0.5 - 150,
+ self._c_height - 350),
+ on_activate_call=self._join_connect_press,
+ autoselect=True)
+ ba.textwidget(edit=self._join_party_code_text,
+ on_return_press_call=btn.activate)
+
+ def _on_get_tickets_press(self) -> None:
+
+ if self._waiting_for_start_stop_response:
+ return
+
+ # Bring up get-tickets window and then kill ourself (we're on the
+ # overlay layer so we'd show up above it).
+ getcurrency.GetCurrencyWindow(modal=True,
+ origin_widget=self._get_tickets_button)
+
+ def _build_host_tab(self) -> None:
+ # pylint: disable=too-many-branches
+ # pylint: disable=too-many-statements
+
+ if _ba.get_account_state() != 'signed_in':
+ ba.textwidget(parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=200,
+ scale=0.8,
+ color=(0.6, 0.56, 0.6),
+ position=(self._c_width * 0.5, self._c_height * 0.5),
+ text=ba.Lstr(resource='notSignedInErrorText'))
+ self._showing_not_signed_in_screen = True
+ return
+ self._showing_not_signed_in_screen = False
+
+ # At first we don't want to show anything until we've gotten a state.
+ # Update: In this situation we now simply show our existing state
+ # but give the start/stop button a loading message and disallow its
+ # use. This keeps things a lot less jumpy looking and allows selecting
+ # playlists/etc without having to wait for the server each time
+ # back to the ui.
+ if self._waiting_for_initial_state and bool(False):
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=200,
+ scale=0.8,
+ color=(0.6, 0.56, 0.6),
+ position=(self._c_width * 0.5, self._c_height * 0.5),
+ text=ba.Lstr(
+ value='${A}...',
+ subs=[('${A}', ba.Lstr(resource='store.loadingText'))],
+ ),
+ )
+ return
+
+ # If we're not currently hosting and hosting requires tickets,
+ # Show our count (possibly with a link to purchase more).
+ if (not self._waiting_for_initial_state
+ and self._hostingstate.party_code is None
+ and self._hostingstate.tickets_to_host_now != 0):
+ if not ba.app.ui.use_toolbars:
+ if ba.app.allow_ticket_purchases:
+ self._get_tickets_button = ba.buttonwidget(
+ parent=self._container,
+ position=(self._c_width - 210 + 125,
+ self._c_height - 44),
+ autoselect=True,
+ scale=0.6,
+ size=(120, 60),
+ textcolor=(0.2, 1, 0.2),
+ label=ba.charstr(ba.SpecialChar.TICKET),
+ color=(0.65, 0.5, 0.8),
+ on_activate_call=self._on_get_tickets_press)
+ else:
+ self._ticket_count_text = ba.textwidget(
+ parent=self._container,
+ scale=0.6,
+ position=(self._c_width - 210 + 125,
+ self._c_height - 44),
+ color=(0.2, 1, 0.2),
+ h_align='center',
+ v_align='center')
+ # Set initial ticket count.
+ self._update_currency_ui()
+
+ v = self._c_height - 90
+ if self._hostingstate.party_code is None:
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=self._c_width * 0.9,
+ scale=0.7,
+ flatness=1.0,
+ color=(0.5, 0.46, 0.5),
+ position=(self._c_width * 0.5, v),
+ text=ba.Lstr(
+ resource='gatherWindow.privatePartyCloudDescriptionText'))
+
+ v -= 100
+ if self._hostingstate.party_code is None:
+ # We've got no current party running; show options to set one up.
+ ba.textwidget(parent=self._container,
+ size=(0, 0),
+ h_align='right',
+ v_align='center',
+ maxwidth=200,
+ scale=0.8,
+ color=(0.6, 0.56, 0.6),
+ position=(self._c_width * 0.5 - 210, v),
+ text=ba.Lstr(resource='playlistText'))
+ self._host_playlist_button = ba.buttonwidget(
+ parent=self._container,
+ size=(400, 70),
+ color=(0.6, 0.5, 0.6),
+ textcolor=(0.8, 0.75, 0.8),
+ label=self._hostingconfig.playlist_name,
+ on_activate_call=self._playlist_press,
+ position=(self._c_width * 0.5 - 200, v - 35),
+ up_widget=self._host_sub_tab_text,
+ autoselect=True)
+
+ # If it appears we're coming back from playlist selection,
+ # re-select our playlist button.
+ if ba.app.ui.selecting_private_party_playlist:
+ ba.containerwidget(edit=self._container,
+ selected_child=self._host_playlist_button)
+ ba.app.ui.selecting_private_party_playlist = False
+ else:
+ # We've got a current party; show its info.
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=600,
+ scale=0.9,
+ color=(0.7, 0.64, 0.7),
+ position=(self._c_width * 0.5, v + 90),
+ text=ba.Lstr(resource='gatherWindow.partyServerRunningText'))
+ ba.textwidget(parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=600,
+ scale=0.7,
+ color=(0.7, 0.64, 0.7),
+ position=(self._c_width * 0.5, v + 50),
+ text=ba.Lstr(resource='gatherWindow.partyCodeText'))
+ ba.textwidget(parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ scale=2.0,
+ color=(0.0, 1.0, 0.0),
+ position=(self._c_width * 0.5, v + 10),
+ text=self._hostingstate.party_code)
+
+ # Also action buttons to copy it and connect to it.
+ if ba.clipboard_is_supported():
+ cbtnoffs = 10
+ self._host_copy_button = ba.buttonwidget(
+ parent=self._container,
+ size=(140, 40),
+ color=(0.6, 0.5, 0.6),
+ textcolor=(0.8, 0.75, 0.8),
+ label=ba.Lstr(resource='gatherWindow.copyCodeText'),
+ on_activate_call=self._host_copy_press,
+ position=(self._c_width * 0.5 - 150, v - 70),
+ autoselect=True)
+ else:
+ cbtnoffs = -70
+ self._host_connect_button = ba.buttonwidget(
+ parent=self._container,
+ size=(140, 40),
+ color=(0.6, 0.5, 0.6),
+ textcolor=(0.8, 0.75, 0.8),
+ label=ba.Lstr(resource='gatherWindow.manualConnectText'),
+ on_activate_call=self._host_connect_press,
+ position=(self._c_width * 0.5 + cbtnoffs, v - 70),
+ autoselect=True)
+
+ v -= 120
+
+ # Line above the main action button:
+
+ # If we don't want to show anything until we get a state:
+ if self._waiting_for_initial_state:
+ pass
+ elif self._hostingstate.unavailable_error is not None:
+ # If hosting is unavailable, show the associated reason.
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=self._c_width * 0.9,
+ scale=0.7,
+ flatness=1.0,
+ color=(1.0, 0.0, 0.0),
+ position=(self._c_width * 0.5, v),
+ text=ba.Lstr(translate=('serverResponses',
+ self._hostingstate.unavailable_error)))
+ elif self._hostingstate.free_host_minutes_remaining is not None:
+ # If we've been pre-approved to start/stop for free, show that.
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=self._c_width * 0.9,
+ scale=0.7,
+ flatness=1.0,
+ color=((0.7, 0.64, 0.7) if self._hostingstate.party_code else
+ (0.0, 1.0, 0.0)),
+ position=(self._c_width * 0.5, v),
+ text=ba.Lstr(
+ resource='gatherWindow.startStopHostingMinutesText',
+ subs=[(
+ '${MINUTES}',
+ f'{self._hostingstate.free_host_minutes_remaining:.0f}'
+ )]))
+ else:
+ # Otherwise tell whether the free cloud server is available
+ # or will be at some point.
+ if self._hostingstate.party_code is None:
+ if self._hostingstate.tickets_to_host_now == 0:
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=self._c_width * 0.9,
+ scale=0.7,
+ flatness=1.0,
+ color=(0.0, 1.0, 0.0),
+ position=(self._c_width * 0.5, v),
+ text=ba.Lstr(
+ resource=
+ 'gatherWindow.freeCloudServerAvailableNowText'))
+ else:
+ if self._hostingstate.minutes_until_free_host is None:
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=self._c_width * 0.9,
+ scale=0.7,
+ flatness=1.0,
+ color=(1.0, 0.6, 0.0),
+ position=(self._c_width * 0.5, v),
+ text=ba.Lstr(
+ resource=
+ 'gatherWindow.freeCloudServerNotAvailableText')
+ )
+ else:
+ availmins = self._hostingstate.minutes_until_free_host
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=self._c_width * 0.9,
+ scale=0.7,
+ flatness=1.0,
+ color=(1.0, 0.6, 0.0),
+ position=(self._c_width * 0.5, v),
+ text=ba.Lstr(resource='gatherWindow.'
+ 'freeCloudServerAvailableMinutesText',
+ subs=[('${MINUTES}',
+ f'{availmins:.0f}')]))
+
+ v -= 100
+
+ if (self._waiting_for_start_stop_response
+ or self._waiting_for_initial_state):
+ btnlabel = ba.Lstr(resource='oneMomentText')
+ else:
+ if self._hostingstate.unavailable_error is not None:
+ btnlabel = ba.Lstr(
+ resource='gatherWindow.hostingUnavailableText')
+ elif self._hostingstate.party_code is None:
+ ticon = _ba.charstr(ba.SpecialChar.TICKET)
+ nowtickets = self._hostingstate.tickets_to_host_now
+ if nowtickets > 0:
+ btnlabel = ba.Lstr(
+ resource='gatherWindow.startHostingPaidText',
+ subs=[('${COST}', f'{ticon}{nowtickets}')])
+ else:
+ btnlabel = ba.Lstr(
+ resource='gatherWindow.startHostingText')
+ else:
+ btnlabel = ba.Lstr(resource='gatherWindow.stopHostingText')
+
+ disabled = (self._hostingstate.unavailable_error is not None
+ or self._waiting_for_initial_state)
+ waiting = self._waiting_for_start_stop_response
+ self._host_start_stop_button = ba.buttonwidget(
+ parent=self._container,
+ size=(400, 80),
+ color=((0.6, 0.6, 0.6) if disabled else
+ (0.5, 1.0, 0.5) if waiting else None),
+ enable_sound=False,
+ label=btnlabel,
+ textcolor=((0.7, 0.7, 0.7) if disabled else None),
+ position=(self._c_width * 0.5 - 200, v),
+ on_activate_call=self._start_stop_button_press,
+ autoselect=True)
+
+ def _playlist_press(self) -> None:
+ assert self._host_playlist_button is not None
+ self.window.playlist_select(origin_widget=self._host_playlist_button)
+
+ def _host_copy_press(self) -> None:
+ assert self._hostingstate.party_code is not None
+ ba.clipboard_set_text(self._hostingstate.party_code)
+ ba.screenmessage(ba.Lstr(resource='gatherWindow.copyCodeConfirmText'))
+
+ def _host_connect_press(self) -> None:
+ assert self._hostingstate.party_code is not None
+ self._connect_to_party_code(self._hostingstate.party_code)
+
+ def _debug_server_comm(self, msg: str) -> None:
+ if DEBUG_SERVER_COMMUNICATION:
+ print(f'PPTABCOM: {msg} at time '
+ f'{time.time()-self._create_time:.2f}')
+
+ def _connect_to_party_code(self, code: str) -> None:
+
+ # Ignore attempted followup sends for a few seconds.
+ # (this will reset if we get a response)
+ now = time.time()
+ if (self._connect_press_time is not None
+ and now - self._connect_press_time < 5.0):
+ self._debug_server_comm(
+ 'not sending private party connect (too soon)')
+ return
+ self._connect_press_time = now
+
+ self._debug_server_comm('sending private party connect')
+ _ba.add_transaction(
+ {
+ 'type': 'PRIVATE_PARTY_CONNECT',
+ 'code': code
+ },
+ callback=ba.WeakCall(self._connect_response),
+ )
+ _ba.run_transactions()
+
+ def _start_stop_button_press(self) -> None:
+ if (self._waiting_for_start_stop_response
+ or self._waiting_for_initial_state):
+ return
+
+ if _ba.get_account_state() != 'signed_in':
+ ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'))
+ ba.playsound(ba.getsound('error'))
+ self._refresh_sub_tab()
+ return
+
+ if self._hostingstate.unavailable_error is not None:
+ ba.playsound(ba.getsound('error'))
+ return
+
+ # If we're not hosting, start.
+ if self._hostingstate.party_code is None:
+
+ # If there's a ticket cost, make sure we have enough tickets.
+ if self._hostingstate.tickets_to_host_now > 0:
+ ticket_count: Optional[int]
+ try:
+ ticket_count = _ba.get_account_ticket_count()
+ except Exception:
+ # FIXME: should add a ba.NotSignedInError we can use here.
+ ticket_count = None
+ ticket_cost = self._hostingstate.tickets_to_host_now
+ if ticket_count is not None and ticket_count < ticket_cost:
+ getcurrency.show_get_tickets_prompt()
+ ba.playsound(ba.getsound('error'))
+ return
+ self._last_action_send_time = time.time()
+ _ba.add_transaction(
+ {
+ 'type': 'PRIVATE_PARTY_START',
+ 'config': asdict(self._hostingconfig)
+ },
+ callback=ba.WeakCall(self._hosting_state_response))
+ _ba.run_transactions()
+
+ else:
+ self._last_action_send_time = time.time()
+ _ba.add_transaction({'type': 'PRIVATE_PARTY_STOP'},
+ callback=ba.WeakCall(
+ self._hosting_state_response))
+ _ba.run_transactions()
+ ba.playsound(ba.getsound('click01'))
+
+ self._waiting_for_start_stop_response = True
+ self._refresh_sub_tab()
+
+ def _join_connect_press(self) -> None:
+
+ # Error immediately if its an empty code.
+ code: Optional[str] = None
+ if self._join_party_code_text:
+ code = cast(str, ba.textwidget(query=self._join_party_code_text))
+ if not code:
+ ba.screenmessage(
+ ba.Lstr(resource='internal.invalidAddressErrorText'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ return
+
+ self._connect_to_party_code(code)
+
+ def _connect_response(self, result: Optional[Dict[str, Any]]) -> None:
+ try:
+ self._connect_press_time = None
+ if result is None:
+ raise RuntimeError()
+ cresult = dataclass_from_dict(ConnectResult, result)
+ if cresult.error is not None:
+ self._debug_server_comm('got error connect response')
+ ba.screenmessage(
+ ba.Lstr(translate=('serverResponses', cresult.error)),
+ (1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ return
+ self._debug_server_comm('got valid connect response')
+ assert cresult.addr is not None and cresult.port is not None
+ _ba.connect_to_party(cresult.addr, port=cresult.port)
+ except Exception:
+ self._debug_server_comm('got connect response error')
+ ba.playsound(ba.getsound('error'))
+
+ def save_state(self) -> None:
+ ba.app.ui.window_states[type(self)] = copy.deepcopy(self._state)
+
+ def restore_state(self) -> None:
+ state = ba.app.ui.window_states.get(type(self))
+ if state is None:
+ state = State()
+ assert isinstance(state, State)
+ self._state = state
diff --git a/assets/src/ba_data/python/bastd/ui/gather/publictab.py b/assets/src/ba_data/python/bastd/ui/gather/publictab.py
new file mode 100644
index 00000000..b1a326ba
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/ui/gather/publictab.py
@@ -0,0 +1,1275 @@
+# Released under the MIT License. See LICENSE for details.
+#
+# pylint: disable=too-many-lines
+"""Defines the public tab in the gather UI."""
+
+from __future__ import annotations
+
+import copy
+import time
+import threading
+from enum import Enum
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, cast
+
+import _ba
+import ba
+from bastd.ui.gather import GatherTab
+
+if TYPE_CHECKING:
+ from typing import Callable, Any, Optional, Dict, Union, Tuple, List
+ from bastd.ui.gather import GatherWindow
+
+# Print a bit of info about pings, queries, etc.
+DEBUG_SERVER_COMMUNICATION = False
+DEBUG_PROCESSING = False
+
+
+class SubTabType(Enum):
+ """Available sub-tabs."""
+ JOIN = 'join'
+ HOST = 'host'
+
+
+@dataclass
+class PartyEntry:
+ """Info about a public party."""
+ address: str
+ index: int
+ queue: Optional[str] = None
+ port: int = -1
+ name: str = ''
+ size: int = -1
+ size_max: int = -1
+ claimed: bool = False
+ ping: Optional[float] = None
+ ping_interval: float = -1.0
+ next_ping_time: float = -1.0
+ ping_attempts: int = 0
+ ping_responses: int = 0
+ stats_addr: Optional[str] = None
+ clean_display_index: Optional[int] = None
+
+ def get_key(self) -> str:
+ """Return the key used to store this party."""
+ return f'{self.address}_{self.port}'
+
+
+class UIRow:
+ """Wrangles UI for a row in the party list."""
+
+ def __init__(self) -> None:
+ self._name_widget: Optional[ba.Widget] = None
+ self._size_widget: Optional[ba.Widget] = None
+ self._ping_widget: Optional[ba.Widget] = None
+ self._stats_button: Optional[ba.Widget] = None
+
+ def __del__(self) -> None:
+ self._clear()
+
+ def _clear(self) -> None:
+ for widget in [
+ self._name_widget, self._size_widget, self._ping_widget,
+ self._stats_button
+ ]:
+ if widget:
+ widget.delete()
+
+ def update(self, index: int, party: PartyEntry, sub_scroll_width: float,
+ sub_scroll_height: float, lineheight: float,
+ columnwidget: ba.Widget, join_text: ba.Widget,
+ filter_text: ba.Widget, existing_selection: Optional[Selection],
+ tab: PublicGatherTab) -> None:
+ """Update for the given data."""
+ # pylint: disable=too-many-locals
+
+ # Quick-out: if we've been marked clean for a certain index and
+ # we're still at that index, we're done.
+ if party.clean_display_index == index:
+ return
+
+ ping_good = _ba.get_account_misc_read_val('pingGood', 100)
+ ping_med = _ba.get_account_misc_read_val('pingMed', 500)
+
+ self._clear()
+ hpos = 20
+ vpos = sub_scroll_height - lineheight * index - 50
+ self._name_widget = ba.textwidget(
+ text=ba.Lstr(value=party.name),
+ parent=columnwidget,
+ size=(sub_scroll_width * 0.63, 20),
+ position=(0 + hpos, 4 + vpos),
+ selectable=True,
+ on_select_call=ba.WeakCall(
+ tab.set_public_party_selection,
+ Selection(party.get_key(), SelectionComponent.NAME)),
+ on_activate_call=ba.WeakCall(tab.on_public_party_activate, party),
+ click_activate=True,
+ maxwidth=sub_scroll_width * 0.45,
+ corner_scale=1.4,
+ autoselect=True,
+ color=(1, 1, 1, 0.3 if party.ping is None else 1.0),
+ h_align='left',
+ v_align='center')
+ ba.widget(edit=self._name_widget,
+ left_widget=join_text,
+ show_buffer_top=64.0,
+ show_buffer_bottom=64.0)
+ if existing_selection == Selection(party.get_key(),
+ SelectionComponent.NAME):
+ ba.containerwidget(edit=columnwidget,
+ selected_child=self._name_widget)
+ if party.stats_addr:
+ url = party.stats_addr.replace(
+ '${ACCOUNT}',
+ _ba.get_account_misc_read_val_2('resolvedAccountID',
+ 'UNKNOWN'))
+ self._stats_button = ba.buttonwidget(
+ color=(0.3, 0.6, 0.94),
+ textcolor=(1.0, 1.0, 1.0),
+ label=ba.Lstr(resource='statsText'),
+ parent=columnwidget,
+ autoselect=True,
+ on_activate_call=ba.Call(ba.open_url, url),
+ on_select_call=ba.WeakCall(
+ tab.set_public_party_selection,
+ Selection(party.get_key(),
+ SelectionComponent.STATS_BUTTON)),
+ size=(120, 40),
+ position=(sub_scroll_width * 0.66 + hpos, 1 + vpos),
+ scale=0.9)
+ if existing_selection == Selection(
+ party.get_key(), SelectionComponent.STATS_BUTTON):
+ ba.containerwidget(edit=columnwidget,
+ selected_child=self._stats_button)
+
+ self._size_widget = ba.textwidget(
+ text=str(party.size) + '/' + str(party.size_max),
+ parent=columnwidget,
+ size=(0, 0),
+ position=(sub_scroll_width * 0.86 + hpos, 20 + vpos),
+ scale=0.7,
+ color=(0.8, 0.8, 0.8),
+ h_align='right',
+ v_align='center')
+
+ if index == 0:
+ ba.widget(edit=self._name_widget, up_widget=filter_text)
+ if self._stats_button:
+ ba.widget(edit=self._stats_button, up_widget=filter_text)
+
+ self._ping_widget = ba.textwidget(parent=columnwidget,
+ size=(0, 0),
+ position=(sub_scroll_width * 0.94 +
+ hpos, 20 + vpos),
+ scale=0.7,
+ h_align='right',
+ v_align='center')
+ if party.ping is None:
+ ba.textwidget(edit=self._ping_widget,
+ text='-',
+ color=(0.5, 0.5, 0.5))
+ else:
+ ba.textwidget(edit=self._ping_widget,
+ text=str(int(party.ping)),
+ color=(0, 1, 0) if party.ping <= ping_good else
+ (1, 1, 0) if party.ping <= ping_med else (1, 0, 0))
+
+ party.clean_display_index = index
+
+
+@dataclass
+class State:
+ """State saved/restored only while the app is running."""
+ sub_tab: SubTabType = SubTabType.JOIN
+ parties: Optional[List[Tuple[str, PartyEntry]]] = None
+ next_entry_index: int = 0
+ filter_value: str = ''
+ have_server_list_response: bool = False
+ have_valid_server_list: bool = False
+
+
+class SelectionComponent(Enum):
+ """Describes what part of an entry is selected."""
+ NAME = 'name'
+ STATS_BUTTON = 'stats_button'
+
+
+@dataclass
+class Selection:
+ """Describes the currently selected list element."""
+ entry_key: str
+ component: SelectionComponent
+
+
+class AddrFetchThread(threading.Thread):
+ """Thread for fetching an address in the bg."""
+
+ def __init__(self, call: Callable[[Any], Any]):
+ super().__init__()
+ self._call = call
+
+ def run(self) -> None:
+ try:
+ # FIXME: Update this to work with IPv6 at some point.
+ import socket
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.connect(('8.8.8.8', 80))
+ val = sock.getsockname()[0]
+ sock.close()
+ ba.pushcall(ba.Call(self._call, val), from_other_thread=True)
+ 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()
+
+
+class PingThread(threading.Thread):
+ """Thread for sending out game pings."""
+
+ def __init__(self, address: str, port: int,
+ call: Callable[[str, int, Optional[float]], Optional[int]]):
+ super().__init__()
+ self._address = address
+ self._port = port
+ self._call = call
+
+ def run(self) -> None:
+ # pylint: disable=too-many-branches
+ # pylint: disable=too-many-statements
+ ba.app.ping_thread_count += 1
+ sock: Optional[socket.socket] = None
+ try:
+ import socket
+ from ba.internal import get_ip_address_type
+ socket_type = get_ip_address_type(self._address)
+ sock = socket.socket(socket_type, socket.SOCK_DGRAM)
+ sock.connect((self._address, self._port))
+
+ accessible = False
+ starttime = time.time()
+
+ # Send a few pings and wait a second for
+ # a response.
+ sock.settimeout(1)
+ for _i in range(3):
+ sock.send(b'\x0b')
+ result: Optional[bytes]
+ try:
+ # 11: BA_PACKET_SIMPLE_PING
+ result = sock.recv(10)
+ except Exception:
+ result = None
+ if result == b'\x0c':
+ # 12: BA_PACKET_SIMPLE_PONG
+ accessible = True
+ break
+ time.sleep(1)
+ ping = (time.time() - starttime) * 1000.0
+ ba.pushcall(ba.Call(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
+
+ # Ignore harmless errors.
+ if exc.errno in {
+ errno.EHOSTUNREACH, errno.ENETUNREACH, errno.EINVAL,
+ errno.EPERM, errno.EACCES
+ }:
+ pass
+ elif exc.errno == 10022:
+ # Windows 'invalid argument' error.
+ pass
+ elif exc.errno == 10051:
+ # Windows 'a socket operation was attempted
+ # to an unreachable network' error.
+ pass
+ elif exc.errno == errno.EADDRNOTAVAIL:
+ if self._port == 0:
+ # This has happened. Ignore.
+ pass
+ elif ba.do_once():
+ print(f'Got EADDRNOTAVAIL on gather ping'
+ f' for addr {self._address}'
+ f' port {self._port}.')
+ else:
+ 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)
+ finally:
+ try:
+ if sock is not None:
+ sock.close()
+ except Exception:
+ ba.print_exception('Error on gather ping cleanup', once=True)
+
+ ba.app.ping_thread_count -= 1
+
+
+class PublicGatherTab(GatherTab):
+ """The public tab in the gather UI"""
+
+ def __init__(self, window: GatherWindow) -> None:
+ super().__init__(window)
+ self._container: Optional[ba.Widget] = None
+ self._join_text: Optional[ba.Widget] = None
+ self._host_text: Optional[ba.Widget] = None
+ self._filter_text: Optional[ba.Widget] = None
+ self._local_address: Optional[str] = None
+ self._last_connect_attempt_time: Optional[float] = None
+ self._sub_tab: SubTabType = SubTabType.JOIN
+ self._selection: Optional[Selection] = None
+ self._refreshing_list = False
+ self._update_timer: Optional[ba.Timer] = None
+ self._host_scrollwidget: Optional[ba.Widget] = None
+ self._host_name_text: Optional[ba.Widget] = None
+ self._host_toggle_button: Optional[ba.Widget] = None
+ self._last_server_list_query_time: Optional[float] = None
+ self._join_list_column: Optional[ba.Widget] = None
+ self._join_status_text: Optional[ba.Widget] = None
+ self._host_max_party_size_value: Optional[ba.Widget] = None
+ self._host_max_party_size_minus_button: (Optional[ba.Widget]) = None
+ self._host_max_party_size_plus_button: (Optional[ba.Widget]) = None
+ self._host_status_text: Optional[ba.Widget] = None
+ self._signed_in = False
+ self._ui_rows: List[UIRow] = []
+ self._refresh_ui_row = 0
+ self._have_user_selected_row = False
+ self._first_valid_server_list_time: Optional[float] = None
+
+ # Parties indexed by id:
+ self._parties: Dict[str, PartyEntry] = {}
+
+ # Parties sorted in display order:
+ self._parties_sorted: List[Tuple[str, PartyEntry]] = []
+ self._party_lists_dirty = True
+
+ # Sorted parties with filter applied:
+ self._parties_displayed: Dict[str, PartyEntry] = {}
+
+ self._next_entry_index = 0
+ self._have_server_list_response = False
+ self._have_valid_server_list = False
+ self._filter_value = ''
+ self._pending_party_infos: List[Dict[str, Any]] = []
+ self._last_sub_scroll_height = 0.0
+
+ def on_activate(
+ self,
+ parent_widget: ba.Widget,
+ tab_button: ba.Widget,
+ region_width: float,
+ region_height: float,
+ region_left: float,
+ region_bottom: float,
+ ) -> ba.Widget:
+ c_width = region_width
+ c_height = region_height - 20
+ self._container = ba.containerwidget(
+ parent=parent_widget,
+ position=(region_left,
+ region_bottom + (region_height - c_height) * 0.5),
+ size=(c_width, c_height),
+ background=False,
+ selection_loops_to_parent=True)
+ v = c_height - 30
+ self._join_text = ba.textwidget(
+ parent=self._container,
+ position=(c_width * 0.5 - 245, v - 13),
+ color=(0.6, 1.0, 0.6),
+ scale=1.3,
+ size=(200, 30),
+ maxwidth=250,
+ h_align='left',
+ v_align='center',
+ click_activate=True,
+ selectable=True,
+ autoselect=True,
+ on_activate_call=lambda: self._set_sub_tab(
+ SubTabType.JOIN,
+ region_width,
+ region_height,
+ playsound=True,
+ ),
+ text=ba.Lstr(resource='gatherWindow.'
+ 'joinPublicPartyDescriptionText'))
+ self._host_text = ba.textwidget(
+ parent=self._container,
+ position=(c_width * 0.5 + 45, v - 13),
+ color=(0.6, 1.0, 0.6),
+ scale=1.3,
+ size=(200, 30),
+ maxwidth=250,
+ h_align='left',
+ v_align='center',
+ click_activate=True,
+ selectable=True,
+ autoselect=True,
+ on_activate_call=lambda: self._set_sub_tab(
+ SubTabType.HOST,
+ region_width,
+ region_height,
+ playsound=True,
+ ),
+ text=ba.Lstr(resource='gatherWindow.'
+ 'hostPublicPartyDescriptionText'))
+ ba.widget(edit=self._join_text, up_widget=tab_button)
+ ba.widget(edit=self._host_text,
+ left_widget=self._join_text,
+ up_widget=tab_button)
+ ba.widget(edit=self._join_text, right_widget=self._host_text)
+
+ # Attempt to fetch our local address so we have it for error messages.
+ if self._local_address is None:
+ AddrFetchThread(ba.WeakCall(self._fetch_local_addr_cb)).start()
+
+ self._set_sub_tab(self._sub_tab, region_width, region_height)
+ self._update_timer = ba.Timer(0.1,
+ ba.WeakCall(self._update),
+ repeat=True,
+ timetype=ba.TimeType.REAL)
+ return self._container
+
+ def on_deactivate(self) -> None:
+ self._update_timer = None
+
+ def save_state(self) -> None:
+
+ # Save off a small number of parties with the lowest ping; we'll
+ # display these immediately when our UI comes back up which should
+ # be enough to make things feel nice and crisp while we do a full
+ # server re-query or whatnot.
+ ba.app.ui.window_states[type(self)] = State(
+ sub_tab=self._sub_tab,
+ parties=[(i, copy.copy(p)) for i, p in self._parties_sorted[:40]],
+ next_entry_index=self._next_entry_index,
+ filter_value=self._filter_value,
+ have_server_list_response=self._have_server_list_response,
+ have_valid_server_list=self._have_valid_server_list)
+
+ def restore_state(self) -> None:
+ state = ba.app.ui.window_states.get(type(self))
+ if state is None:
+ state = State()
+ assert isinstance(state, State)
+ self._sub_tab = state.sub_tab
+
+ # Restore the parties we stored.
+ if state.parties:
+ self._parties = {
+ key: copy.copy(party)
+ for key, party in state.parties
+ }
+ self._parties_sorted = list(self._parties.items())
+ self._party_lists_dirty = True
+
+ self._next_entry_index = state.next_entry_index
+
+ # FIXME: should save/restore these too?..
+ self._have_server_list_response = state.have_server_list_response
+ self._have_valid_server_list = state.have_valid_server_list
+ self._filter_value = state.filter_value
+
+ def _set_sub_tab(self,
+ value: SubTabType,
+ region_width: float,
+ region_height: float,
+ playsound: bool = False) -> None:
+ assert self._container
+ if playsound:
+ ba.playsound(ba.getsound('click01'))
+
+ # Reset our selection.
+ # (prevents selecting something way down the list if we switched away
+ # and came back)
+ self._selection = None
+ self._have_user_selected_row = False
+
+ # Reset refresh to the top and make sure everything refreshes.
+ self._refresh_ui_row = 0
+ for party in self._parties.values():
+ party.clean_display_index = None
+
+ self._sub_tab = value
+ active_color = (0.6, 1.0, 0.6)
+ inactive_color = (0.5, 0.4, 0.5)
+ ba.textwidget(
+ edit=self._join_text,
+ color=active_color if value is SubTabType.JOIN else inactive_color)
+ ba.textwidget(
+ edit=self._host_text,
+ color=active_color if value is SubTabType.HOST else inactive_color)
+
+ # Clear anything existing in the old sub-tab.
+ for widget in self._container.get_children():
+ if widget and widget not in {self._host_text, self._join_text}:
+ widget.delete()
+
+ if value is SubTabType.JOIN:
+ self._build_join_tab(region_width, region_height)
+
+ if value is SubTabType.HOST:
+ self._build_host_tab(region_width, region_height)
+
+ def _build_join_tab(self, region_width: float,
+ region_height: float) -> None:
+ c_width = region_width
+ c_height = region_height - 20
+ sub_scroll_height = c_height - 125
+ sub_scroll_width = 830
+ v = c_height - 35
+ v -= 60
+ filter_txt = ba.Lstr(resource='filterText')
+ self._filter_text = ba.textwidget(parent=self._container,
+ text=self._filter_value,
+ size=(350, 45),
+ position=(290, v - 10),
+ h_align='left',
+ v_align='center',
+ editable=True,
+ description=filter_txt)
+ ba.widget(edit=self._filter_text, up_widget=self._join_text)
+ ba.textwidget(text=filter_txt,
+ parent=self._container,
+ size=(0, 0),
+ position=(270, v + 13),
+ maxwidth=150,
+ scale=0.8,
+ color=(0.5, 0.46, 0.5),
+ flatness=1.0,
+ h_align='right',
+ v_align='center')
+
+ ba.textwidget(text=ba.Lstr(resource='nameText'),
+ parent=self._container,
+ size=(0, 0),
+ position=(90, v - 8),
+ maxwidth=60,
+ scale=0.6,
+ color=(0.5, 0.46, 0.5),
+ flatness=1.0,
+ h_align='center',
+ v_align='center')
+ ba.textwidget(text=ba.Lstr(resource='gatherWindow.partySizeText'),
+ parent=self._container,
+ size=(0, 0),
+ position=(755, v - 8),
+ maxwidth=60,
+ scale=0.6,
+ color=(0.5, 0.46, 0.5),
+ flatness=1.0,
+ h_align='center',
+ v_align='center')
+ ba.textwidget(text=ba.Lstr(resource='gatherWindow.pingText'),
+ parent=self._container,
+ size=(0, 0),
+ position=(825, v - 8),
+ maxwidth=60,
+ scale=0.6,
+ color=(0.5, 0.46, 0.5),
+ flatness=1.0,
+ h_align='center',
+ v_align='center')
+ v -= sub_scroll_height + 23
+ self._host_scrollwidget = scrollw = ba.scrollwidget(
+ parent=self._container,
+ simple_culling_v=10,
+ position=((c_width - sub_scroll_width) * 0.5, v),
+ size=(sub_scroll_width, sub_scroll_height),
+ claims_up_down=False,
+ claims_left_right=True,
+ autoselect=True)
+ self._join_list_column = ba.containerwidget(parent=scrollw,
+ background=False,
+ size=(400, 400),
+ claims_left_right=True)
+ self._join_status_text = ba.textwidget(parent=self._container,
+ text='',
+ size=(0, 0),
+ scale=0.9,
+ flatness=1.0,
+ shadow=0.0,
+ h_align='center',
+ v_align='top',
+ maxwidth=c_width,
+ color=(0.6, 0.6, 0.6),
+ position=(c_width * 0.5,
+ c_height * 0.5))
+
+ def _build_host_tab(self, region_width: float,
+ region_height: float) -> None:
+ c_width = region_width
+ c_height = region_height - 20
+ v = c_height - 35
+ v -= 25
+ is_public_enabled = _ba.get_public_party_enabled()
+ v -= 30
+
+ ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ maxwidth=c_width * 0.9,
+ scale=0.7,
+ flatness=1.0,
+ color=(0.5, 0.46, 0.5),
+ position=(region_width * 0.5, v + 10),
+ text=ba.Lstr(resource='gatherWindow.publicHostRouterConfigText'))
+ v -= 30
+
+ party_name_text = ba.Lstr(
+ resource='gatherWindow.partyNameText',
+ fallback_resource='editGameListWindow.nameText')
+ ba.textwidget(parent=self._container,
+ size=(0, 0),
+ h_align='right',
+ v_align='center',
+ maxwidth=200,
+ scale=0.8,
+ color=ba.app.ui.infotextcolor,
+ position=(210, v - 9),
+ text=party_name_text)
+ self._host_name_text = ba.textwidget(parent=self._container,
+ editable=True,
+ size=(535, 40),
+ position=(230, v - 30),
+ text=ba.app.config.get(
+ 'Public Party Name', ''),
+ maxwidth=494,
+ shadow=0.3,
+ flatness=1.0,
+ description=party_name_text,
+ autoselect=True,
+ v_align='center',
+ corner_scale=1.0)
+
+ v -= 60
+ ba.textwidget(parent=self._container,
+ size=(0, 0),
+ h_align='right',
+ v_align='center',
+ maxwidth=200,
+ scale=0.8,
+ color=ba.app.ui.infotextcolor,
+ position=(210, v - 9),
+ text=ba.Lstr(resource='maxPartySizeText',
+ fallback_resource='maxConnectionsText'))
+ self._host_max_party_size_value = ba.textwidget(
+ parent=self._container,
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ scale=1.2,
+ color=(1, 1, 1),
+ position=(240, v - 9),
+ text=str(_ba.get_public_party_max_size()))
+ btn1 = self._host_max_party_size_minus_button = (ba.buttonwidget(
+ parent=self._container,
+ size=(40, 40),
+ on_activate_call=ba.WeakCall(
+ self._on_max_public_party_size_minus_press),
+ position=(280, v - 26),
+ label='-',
+ autoselect=True))
+ btn2 = self._host_max_party_size_plus_button = (ba.buttonwidget(
+ parent=self._container,
+ size=(40, 40),
+ on_activate_call=ba.WeakCall(
+ self._on_max_public_party_size_plus_press),
+ position=(350, v - 26),
+ label='+',
+ autoselect=True))
+ v -= 50
+ v -= 70
+ if is_public_enabled:
+ label = ba.Lstr(
+ resource='gatherWindow.makePartyPrivateText',
+ fallback_resource='gatherWindow.stopAdvertisingText')
+ else:
+ label = ba.Lstr(
+ resource='gatherWindow.makePartyPublicText',
+ fallback_resource='gatherWindow.startAdvertisingText')
+ self._host_toggle_button = ba.buttonwidget(
+ parent=self._container,
+ label=label,
+ size=(400, 80),
+ on_activate_call=self._on_stop_advertising_press
+ if is_public_enabled else self._on_start_advertizing_press,
+ position=(c_width * 0.5 - 200, v),
+ autoselect=True,
+ up_widget=btn2)
+ ba.widget(edit=self._host_name_text, down_widget=btn2)
+ ba.widget(edit=btn2, up_widget=self._host_name_text)
+ ba.widget(edit=btn1, up_widget=self._host_name_text)
+ ba.widget(edit=self._join_text, down_widget=self._host_name_text)
+ v -= 10
+ self._host_status_text = ba.textwidget(
+ parent=self._container,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'partyStatusNotPublicText'),
+ size=(0, 0),
+ scale=0.7,
+ flatness=1.0,
+ h_align='center',
+ v_align='top',
+ maxwidth=c_width * 0.9,
+ color=(0.6, 0.56, 0.6),
+ position=(c_width * 0.5, v))
+ v -= 90
+ ba.textwidget(
+ parent=self._container,
+ text=ba.Lstr(resource='gatherWindow.dedicatedServerInfoText'),
+ size=(0, 0),
+ scale=0.7,
+ flatness=1.0,
+ h_align='center',
+ v_align='center',
+ maxwidth=c_width * 0.9,
+ color=(0.5, 0.46, 0.5),
+ position=(c_width * 0.5, v))
+
+ # If public sharing is already on,
+ # launch a status-check immediately.
+ if _ba.get_public_party_enabled():
+ self._do_status_check()
+
+ def _on_public_party_query_result(
+ self, result: Optional[Dict[str, Any]]) -> None:
+ starttime = time.time()
+ self._have_server_list_response = True
+
+ if result is None:
+ self._have_valid_server_list = False
+ return
+
+ if not self._have_valid_server_list:
+ self._first_valid_server_list_time = time.time()
+
+ self._have_valid_server_list = True
+ parties_in = result['l']
+
+ assert isinstance(parties_in, list)
+ self._pending_party_infos += parties_in
+
+ # To avoid causing a stutter here, we do most processing of
+ # these entries incrementally in our _update() method.
+ # The one thing we do here is prune parties not contained in
+ # this result.
+ for partyval in list(self._parties.values()):
+ partyval.claimed = False
+ for party_in in parties_in:
+ addr = party_in['a']
+ assert isinstance(addr, str)
+ port = party_in['p']
+ assert isinstance(port, int)
+ party_key = f'{addr}_{port}'
+ party = self._parties.get(party_key)
+ if party is not None:
+ party.claimed = True
+ self._parties = {
+ key: val
+ for key, val in list(self._parties.items()) if val.claimed
+ }
+ self._parties_sorted = [
+ p for p in self._parties_sorted if p[1].claimed
+ ]
+ self._party_lists_dirty = True
+
+ # self._update_server_list()
+ if DEBUG_PROCESSING:
+ print(f'Handled public party query results in '
+ f'{time.time()-starttime:.5f}s.')
+
+ def _update(self) -> None:
+ """Periodic updating."""
+
+ # Special case: if a party-queue window is up, don't do any of this
+ # (keeps things smoother).
+ # if ba.app.ui.have_party_queue_window:
+ # return
+
+ if self._sub_tab is SubTabType.JOIN:
+
+ # Keep our filter-text up to date from the UI.
+ text = self._filter_text
+ if text:
+ filter_value = cast(str, ba.textwidget(query=text))
+ if filter_value != self._filter_value:
+ self._filter_value = filter_value
+ self._party_lists_dirty = True
+
+ # Also wipe out party clean-row states.
+ # (otherwise if a party disappears from a row due to
+ # filtering and then reappears on that same row when
+ # the filter is removed it may not update)
+ for party in self._parties.values():
+ party.clean_display_index = None
+
+ self._query_party_list_periodically()
+ self._ping_parties_periodically()
+
+ # If any new party infos have come in, apply some of them.
+ self._process_pending_party_infos()
+
+ # Anytime we sign in/out, make sure we refresh our list.
+ signed_in = _ba.get_account_state() == 'signed_in'
+ if self._signed_in != signed_in:
+ self._signed_in = signed_in
+ self._party_lists_dirty = True
+
+ # Update sorting to account for ping updates, new parties, etc.
+ self._update_party_lists()
+
+ # If we've got a party-name text widget, keep its value plugged
+ # into our public host name.
+ text = self._host_name_text
+ if text:
+ name = cast(str, ba.textwidget(query=self._host_name_text))
+ _ba.set_public_party_name(name)
+
+ # Update status text.
+ status_text = self._join_status_text
+ if status_text:
+ if not signed_in:
+ ba.textwidget(edit=status_text,
+ text=ba.Lstr(resource='notSignedInText'))
+ else:
+ # If we have a valid list, show no status; just the list.
+ # Otherwise show either 'loading...' or 'error' depending
+ # on whether this is our first go-round.
+ if self._have_valid_server_list:
+ ba.textwidget(edit=status_text, text='')
+ else:
+ if self._have_server_list_response:
+ ba.textwidget(edit=status_text,
+ text=ba.Lstr(resource='errorText'))
+ else:
+ ba.textwidget(
+ edit=status_text,
+ text=ba.Lstr(
+ value='${A}...',
+ subs=[('${A}',
+ ba.Lstr(resource='store.loadingText'))],
+ ))
+
+ self._update_party_rows()
+
+ def _update_party_rows(self) -> None:
+ columnwidget = self._join_list_column
+ if not columnwidget:
+ return
+
+ assert self._join_text
+ assert self._filter_text
+
+ # Janky - allow escaping when there's nothing in our list.
+ assert self._host_scrollwidget
+ ba.containerwidget(edit=self._host_scrollwidget,
+ claims_up_down=(len(self._parties_displayed) > 0))
+
+ # Clip if we have more UI rows than parties to show.
+ clipcount = len(self._ui_rows) - len(self._parties_displayed)
+ if clipcount > 0:
+ clipcount = max(clipcount, 50)
+ self._ui_rows = self._ui_rows[:-clipcount]
+
+ # If we have no parties to show, we're done.
+ if not self._parties_displayed:
+ return
+
+ sub_scroll_width = 830
+ lineheight = 42
+ sub_scroll_height = lineheight * len(self._parties_displayed) + 50
+ ba.containerwidget(edit=columnwidget,
+ size=(sub_scroll_width, sub_scroll_height))
+
+ # Any time our height changes, reset the refresh back to the top
+ # so we don't see ugly empty spaces appearing during initial list
+ # filling.
+ if sub_scroll_height != self._last_sub_scroll_height:
+ self._refresh_ui_row = 0
+ self._last_sub_scroll_height = sub_scroll_height
+
+ # Also note that we need to redisplay everything since its pos
+ # will have changed.. :(
+ for party in self._parties.values():
+ party.clean_display_index = None
+
+ # Ew; this rebuilding generates deferred selection callbacks
+ # so we need to push deferred notices so we know to ignore them.
+ def refresh_on() -> None:
+ self._refreshing_list = True
+
+ ba.pushcall(refresh_on)
+
+ # Ok, now here's the deal: we want to avoid creating/updating this
+ # entire list at one time because it will lead to hitches. So we
+ # refresh individual rows quickly in a loop.
+ rowcount = min(12, len(self._parties_displayed))
+
+ party_vals_displayed = list(self._parties_displayed.values())
+ while rowcount > 0:
+ refresh_row = self._refresh_ui_row % len(self._parties_displayed)
+ if refresh_row >= len(self._ui_rows):
+ self._ui_rows.append(UIRow())
+ refresh_row = len(self._ui_rows) - 1
+
+ # For the first few seconds after getting our first server-list,
+ # refresh only the top section of the list; this allows the lowest
+ # ping servers to show up more quickly.
+ if self._first_valid_server_list_time is not None:
+ if time.time() - self._first_valid_server_list_time < 4.0:
+ if refresh_row > 40:
+ refresh_row = 0
+
+ self._ui_rows[refresh_row].update(
+ refresh_row,
+ party_vals_displayed[refresh_row],
+ sub_scroll_width=sub_scroll_width,
+ sub_scroll_height=sub_scroll_height,
+ lineheight=lineheight,
+ columnwidget=columnwidget,
+ join_text=self._join_text,
+ existing_selection=self._selection,
+ filter_text=self._filter_text,
+ tab=self)
+ self._refresh_ui_row = refresh_row + 1
+ rowcount -= 1
+
+ # So our selection callbacks can start firing..
+ def refresh_off() -> None:
+ self._refreshing_list = False
+
+ ba.pushcall(refresh_off)
+
+ def _process_pending_party_infos(self) -> None:
+ starttime = time.time()
+
+ # We want to do this in small enough pieces to not cause UI hitches.
+ chunksize = 30
+ parties_in = self._pending_party_infos[:chunksize]
+ self._pending_party_infos = self._pending_party_infos[chunksize:]
+ for party_in in parties_in:
+ addr = party_in['a']
+ assert isinstance(addr, str)
+ port = party_in['p']
+ assert isinstance(port, int)
+ party_key = f'{addr}_{port}'
+ party = self._parties.get(party_key)
+ if party is None:
+ # If this party is new to us, init it.
+ party = PartyEntry(address=addr,
+ next_ping_time=ba.time(ba.TimeType.REAL) +
+ 0.001 * party_in['pd'],
+ index=self._next_entry_index)
+ self._parties[party_key] = party
+ self._parties_sorted.append((party_key, party))
+ self._party_lists_dirty = True
+ self._next_entry_index += 1
+ assert isinstance(party.address, str)
+ assert isinstance(party.next_ping_time, float)
+
+ # Now, new or not, update its values.
+ party.queue = party_in.get('q')
+ assert isinstance(party.queue, (str, type(None)))
+ party.port = port
+ party.name = party_in['n']
+ assert isinstance(party.name, str)
+ party.size = party_in['s']
+ assert isinstance(party.size, int)
+ party.size_max = party_in['sm']
+ assert isinstance(party.size_max, int)
+
+ # Server provides this in milliseconds; we use seconds.
+ party.ping_interval = 0.001 * party_in['pi']
+ assert isinstance(party.ping_interval, float)
+ party.stats_addr = party_in['sa']
+ assert isinstance(party.stats_addr, (str, type(None)))
+
+ # Make sure the party's UI gets updated.
+ party.clean_display_index = None
+
+ if DEBUG_PROCESSING and parties_in:
+ print(f'Processed {len(parties_in)} raw party infos in'
+ f' {time.time()-starttime:.5f}s.')
+
+ def _update_party_lists(self) -> None:
+ if not self._party_lists_dirty:
+ return
+ starttime = time.time()
+ assert len(self._parties_sorted) == len(self._parties)
+
+ self._parties_sorted.sort(key=lambda p: (
+ p[1].queue is None, # Show non-queued last.
+ p[1].ping if p[1].ping is not None else 999999.0,
+ p[1].index))
+
+ # If signed out or errored, show no parties.
+ if (_ba.get_account_state() != 'signed_in'
+ or not self._have_valid_server_list):
+ self._parties_displayed = {}
+ else:
+ if self._filter_value:
+ filterval = self._filter_value.lower()
+ self._parties_displayed = {
+ k: v
+ for k, v in self._parties_sorted
+ if filterval in v.name.lower()
+ }
+ else:
+ self._parties_displayed = dict(self._parties_sorted)
+
+ # Any time our selection disappears from the displayed list, go back to
+ # auto-selecting the top entry.
+ if (self._selection is not None
+ and self._selection.entry_key not in self._parties_displayed):
+ self._have_user_selected_row = False
+
+ # Whenever the user hasn't selected something, keep the first visible
+ # row selected.
+ if not self._have_user_selected_row and self._parties_displayed:
+ firstpartykey = next(iter(self._parties_displayed))
+ self._selection = Selection(firstpartykey, SelectionComponent.NAME)
+
+ self._party_lists_dirty = False
+ if DEBUG_PROCESSING:
+ print(f'Sorted {len(self._parties_sorted)} parties in'
+ f' {time.time()-starttime:.5f}s.')
+
+ def _query_party_list_periodically(self) -> None:
+ now = ba.time(ba.TimeType.REAL)
+
+ # Fire off a new public-party query periodically.
+ if (self._last_server_list_query_time is None
+ or now - self._last_server_list_query_time > 0.001 *
+ _ba.get_account_misc_read_val('pubPartyRefreshMS', 10000)):
+ self._last_server_list_query_time = now
+ if DEBUG_SERVER_COMMUNICATION:
+ print('REQUESTING SERVER LIST')
+ if _ba.get_account_state() == 'signed_in':
+ _ba.add_transaction(
+ {
+ 'type': 'PUBLIC_PARTY_QUERY',
+ 'proto': ba.app.protocol_version,
+ 'lang': ba.app.lang.language
+ },
+ callback=ba.WeakCall(self._on_public_party_query_result))
+ _ba.run_transactions()
+ else:
+ self._on_public_party_query_result(None)
+
+ def _ping_parties_periodically(self) -> None:
+ now = ba.time(ba.TimeType.REAL)
+
+ # Go through our existing public party entries firing off pings
+ # for any that have timed out.
+ for party in list(self._parties.values()):
+ if party.next_ping_time <= now and ba.app.ping_thread_count < 15:
+
+ # Crank the interval up for high-latency or non-responding
+ # parties to save us some useless work.
+ mult = 1
+ if party.ping_responses == 0:
+ if party.ping_attempts > 4:
+ mult = 10
+ elif party.ping_attempts > 2:
+ mult = 5
+ if party.ping is not None:
+ mult = (10 if party.ping > 300 else
+ 5 if party.ping > 150 else 2)
+
+ interval = party.ping_interval * mult
+ if DEBUG_SERVER_COMMUNICATION:
+ print(f'pinging #{party.index} cur={party.ping} '
+ f'interval={interval} '
+ f'({party.ping_responses}/{party.ping_attempts})')
+
+ party.next_ping_time = now + party.ping_interval * mult
+ party.ping_attempts += 1
+
+ PingThread(party.address, party.port,
+ ba.WeakCall(self._ping_callback)).start()
+
+ def _ping_callback(self, address: str, port: Optional[int],
+ result: Optional[float]) -> None:
+ # Look for a widget corresponding to this target.
+ # If we find one, update our list.
+ party_key = f'{address}_{port}'
+ party = self._parties.get(party_key)
+ if party is not None:
+ if result is not None:
+ party.ping_responses += 1
+
+ # We now smooth ping a bit to reduce jumping around in the list
+ # (only where pings are relatively good).
+ current_ping = party.ping
+ if (current_ping is not None and result is not None
+ and result < 150):
+ smoothing = 0.7
+ party.ping = (smoothing * current_ping +
+ (1.0 - smoothing) * result)
+ else:
+ party.ping = result
+
+ # Need to re-sort the list and update the row display.
+ party.clean_display_index = None
+ self._party_lists_dirty = True
+
+ def _fetch_local_addr_cb(self, val: str) -> None:
+ self._local_address = str(val)
+
+ def _on_public_party_accessible_response(
+ self, data: Optional[Dict[str, Any]]) -> None:
+
+ # If we've got status text widgets, update them.
+ text = self._host_status_text
+ if text:
+ if data is None:
+ ba.textwidget(
+ edit=text,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'partyStatusNoConnectionText'),
+ color=(1, 0, 0),
+ )
+ else:
+ if not data.get('accessible', False):
+ ex_line: Union[str, ba.Lstr]
+ if self._local_address is not None:
+ ex_line = ba.Lstr(
+ value='\n${A} ${B}',
+ subs=[('${A}',
+ ba.Lstr(resource='gatherWindow.'
+ 'manualYourLocalAddressText')),
+ ('${B}', self._local_address)])
+ else:
+ ex_line = ''
+ ba.textwidget(
+ edit=text,
+ text=ba.Lstr(
+ value='${A}\n${B}${C}',
+ subs=[('${A}',
+ ba.Lstr(resource='gatherWindow.'
+ 'partyStatusNotJoinableText')),
+ ('${B}',
+ ba.Lstr(resource='gatherWindow.'
+ 'manualRouterForwardingText',
+ subs=[('${PORT}',
+ str(_ba.get_game_port()))])),
+ ('${C}', ex_line)]),
+ color=(1, 0, 0))
+ else:
+ ba.textwidget(edit=text,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'partyStatusJoinableText'),
+ color=(0, 1, 0))
+
+ def _do_status_check(self) -> None:
+ from ba.internal import master_server_get
+ ba.textwidget(edit=self._host_status_text,
+ color=(1, 1, 0),
+ text=ba.Lstr(resource='gatherWindow.'
+ 'partyStatusCheckingText'))
+ master_server_get('bsAccessCheck', {'b': ba.app.build_number},
+ callback=ba.WeakCall(
+ self._on_public_party_accessible_response))
+
+ def _on_start_advertizing_press(self) -> None:
+ from bastd.ui.account import show_sign_in_prompt
+ if _ba.get_account_state() != 'signed_in':
+ show_sign_in_prompt()
+ return
+
+ name = cast(str, ba.textwidget(query=self._host_name_text))
+ if name == '':
+ ba.screenmessage(ba.Lstr(resource='internal.invalidNameErrorText'),
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ return
+ _ba.set_public_party_name(name)
+ cfg = ba.app.config
+ cfg['Public Party Name'] = name
+ cfg.commit()
+ ba.playsound(ba.getsound('shieldUp'))
+ _ba.set_public_party_enabled(True)
+
+ # In GUI builds we want to authenticate clients only when hosting
+ # public parties.
+ _ba.set_authenticate_clients(True)
+
+ self._do_status_check()
+ ba.buttonwidget(
+ edit=self._host_toggle_button,
+ label=ba.Lstr(
+ resource='gatherWindow.makePartyPrivateText',
+ fallback_resource='gatherWindow.stopAdvertisingText'),
+ on_activate_call=self._on_stop_advertising_press)
+
+ def _on_stop_advertising_press(self) -> None:
+ _ba.set_public_party_enabled(False)
+
+ # In GUI builds we want to authenticate clients only when hosting
+ # public parties.
+ _ba.set_authenticate_clients(False)
+ ba.playsound(ba.getsound('shieldDown'))
+ text = self._host_status_text
+ if text:
+ ba.textwidget(
+ edit=text,
+ text=ba.Lstr(resource='gatherWindow.'
+ 'partyStatusNotPublicText'),
+ color=(0.6, 0.6, 0.6),
+ )
+ ba.buttonwidget(
+ edit=self._host_toggle_button,
+ label=ba.Lstr(
+ resource='gatherWindow.makePartyPublicText',
+ fallback_resource='gatherWindow.startAdvertisingText'),
+ on_activate_call=self._on_start_advertizing_press)
+
+ def on_public_party_activate(self, party: PartyEntry) -> None:
+ """Called when a party is clicked or otherwise activated."""
+ if party.queue is not None:
+ from bastd.ui.partyqueue import PartyQueueWindow
+ ba.playsound(ba.getsound('swish'))
+ PartyQueueWindow(party.queue, party.address, party.port)
+ else:
+ address = party.address
+ port = party.port
+
+ # Rate limit this a bit.
+ now = time.time()
+ last_connect_time = self._last_connect_attempt_time
+ if last_connect_time is None or now - last_connect_time > 2.0:
+ _ba.connect_to_party(address, port=port)
+ self._last_connect_attempt_time = now
+
+ def set_public_party_selection(self, sel: Selection) -> None:
+ """Set the sel."""
+ if self._refreshing_list:
+ return
+ self._selection = sel
+ self._have_user_selected_row = True
+
+ def _on_max_public_party_size_minus_press(self) -> None:
+ val = _ba.get_public_party_max_size()
+ val -= 1
+ if val < 1:
+ val = 1
+ _ba.set_public_party_max_size(val)
+ ba.textwidget(edit=self._host_max_party_size_value, text=str(val))
+
+ def _on_max_public_party_size_plus_press(self) -> None:
+ val = _ba.get_public_party_max_size()
+ val += 1
+ _ba.set_public_party_max_size(val)
+ ba.textwidget(edit=self._host_max_party_size_value, text=str(val))
diff --git a/assets/src/ba_data/python/bastd/ui/getcurrency.py b/assets/src/ba_data/python/bastd/ui/getcurrency.py
index b25457cb..db19be22 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
@@ -65,23 +47,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.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
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,
@@ -98,7 +82,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',
@@ -523,7 +507,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 +517,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:
@@ -566,7 +551,6 @@ class GetCurrencyWindow(ba.Window):
# actually start the purchase locally..
def _do_purchase(self, item: str) -> None:
- from ba.internal import show_ad
if item == 'ad':
import datetime
# if ads are disabled until some time, error..
@@ -583,7 +567,7 @@ class GetCurrencyWindow(ba.Window):
resource='getTicketsWindow.unavailableTemporarilyText'),
color=(1, 0, 0))
elif self._enable_ad_button:
- show_ad('tickets')
+ _ba.app.ads.show_ad('tickets')
else:
_ba.purchase(item)
@@ -599,17 +583,29 @@ 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
def show_get_tickets_prompt() -> None:
- """Show a prompt to get more currency."""
- from bastd.ui import confirm
- confirm.ConfirmWindow(
- ba.Lstr(translate=('serverResponses',
- 'You don\'t have enough tickets for this!')),
- lambda: GetCurrencyWindow(modal=True),
- ok_text=ba.Lstr(resource='getTicketsWindow.titleText'),
- width=460,
- height=130)
+ """Show a 'not enough tickets' prompt with an option to purchase more.
+
+ Note that the purchase option may not always be available
+ depending on the build of the game.
+ """
+ from bastd.ui.confirm import ConfirmWindow
+ if ba.app.allow_ticket_purchases:
+ ConfirmWindow(
+ ba.Lstr(translate=('serverResponses',
+ 'You don\'t have enough tickets for this!')),
+ lambda: GetCurrencyWindow(modal=True),
+ ok_text=ba.Lstr(resource='getTicketsWindow.titleText'),
+ width=460,
+ height=130)
+ else:
+ ConfirmWindow(
+ ba.Lstr(translate=('serverResponses',
+ 'You don\'t have enough tickets for this!')),
+ cancel_button=False,
+ width=460,
+ height=130)
diff --git a/assets/src/ba_data/python/bastd/ui/getremote.py b/assets/src/ba_data/python/bastd/ui/getremote.py
index 4474afe1..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
@@ -36,7 +18,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.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
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..b49e51c8 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
@@ -40,7 +22,6 @@ class HelpWindow(ba.Window):
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
from ba.internal import get_remote_app_name
- from ba.deprecated import get_resource
ba.set_analytics_screen('Help Window')
# If they provided an origin-widget, scale up from that.
@@ -56,40 +37,45 @@ class HelpWindow(ba.Window):
self._r = 'helpWindow'
+ getres = ba.app.lang.get_resource
+
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.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
+ 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}',
ba.Lstr(resource='titleText'))]),
- color=ba.app.title_color,
+ color=ba.app.ui.title_color,
h_align='center',
v_align='top')
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:
+ 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,
@@ -97,7 +83,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.ui.use_toolbars:
ba.containerwidget(edit=self._root_widget,
on_cancel_call=self._close)
ba.widget(edit=self._scrollwidget,
@@ -105,10 +91,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,11 +111,9 @@ 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(
+ self._sub_height = 1590 + ba.app.lang.get_resource(
+ self._r + '.someDaysExtraSpace') + ba.app.lang.get_resource(
self._r + '.orPunchingSomethingExtraSpace')
self._subcontainer = ba.containerwidget(parent=self._scrollwidget,
@@ -227,8 +213,7 @@ class HelpWindow(ba.Window):
color=paragraph,
v_align='center',
flatness=1.0)
- v -= (spacing * 25.0 +
- get_resource(self._r + '.someDaysExtraSpace'))
+ v -= (spacing * 25.0 + getres(self._r + '.someDaysExtraSpace'))
txt_scale = 0.66
txt = ba.Lstr(resource=self._r +
'.orPunchingSomethingText').evaluate()
@@ -243,7 +228,7 @@ class HelpWindow(ba.Window):
v_align='center',
flatness=1.0)
v -= (spacing * 27.0 +
- get_resource(self._r + '.orPunchingSomethingExtraSpace'))
+ getres(self._r + '.orPunchingSomethingExtraSpace'))
txt_scale = 1.0
txt = ba.Lstr(resource=self._r + '.canHelpText',
subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))
@@ -402,7 +387,7 @@ class HelpWindow(ba.Window):
texture=ba.gettexture('buttonPunch'),
color=(1, 0.7, 0.3))
- txt_scale = get_resource(self._r + '.punchInfoTextScale')
+ txt_scale = getres(self._r + '.punchInfoTextScale')
txt = ba.Lstr(resource=self._r + '.punchInfoText').evaluate()
ba.textwidget(parent=self._subcontainer,
position=(h - sep - 185 + 70, v + 120),
@@ -424,7 +409,7 @@ class HelpWindow(ba.Window):
color=(1, 0.3, 0.3))
txt = ba.Lstr(resource=self._r + '.bombInfoText').evaluate()
- txt_scale = get_resource(self._r + '.bombInfoTextScale')
+ txt_scale = getres(self._r + '.bombInfoTextScale')
ba.textwidget(parent=self._subcontainer,
position=(h + sep + 50 + 60, v - 35),
size=(0, 0),
@@ -446,7 +431,7 @@ class HelpWindow(ba.Window):
color=(0.5, 0.5, 1))
txtl = ba.Lstr(resource=self._r + '.pickUpInfoText')
- txt_scale = get_resource(self._r + '.pickUpInfoTextScale')
+ txt_scale = getres(self._r + '.pickUpInfoTextScale')
ba.textwidget(parent=self._subcontainer,
position=(h + 60 + 120, v + sep + 50),
size=(0, 0),
@@ -467,7 +452,7 @@ class HelpWindow(ba.Window):
color=(0.4, 1, 0.4))
txt = ba.Lstr(resource=self._r + '.jumpInfoText').evaluate()
- txt_scale = get_resource(self._r + '.jumpInfoTextScale')
+ txt_scale = getres(self._r + '.jumpInfoTextScale')
ba.textwidget(parent=self._subcontainer,
position=(h - 250 + 75, v - sep - 15 + 30),
size=(0, 0),
@@ -479,7 +464,7 @@ class HelpWindow(ba.Window):
v_align='top')
txt = ba.Lstr(resource=self._r + '.runInfoText').evaluate()
- txt_scale = get_resource(self._r + '.runInfoTextScale')
+ txt_scale = getres(self._r + '.runInfoTextScale')
ba.textwidget(parent=self._subcontainer,
position=(h, v - sep - 100),
size=(0, 0),
@@ -518,7 +503,7 @@ class HelpWindow(ba.Window):
texture=logo_tex)
v -= spacing * 50.0
- txt_scale = get_resource(self._r + '.powerupsSubtitleTextScale')
+ txt_scale = getres(self._r + '.powerupsSubtitleTextScale')
txt = ba.Lstr(resource=self._r + '.powerupsSubtitleText').evaluate()
ba.textwidget(parent=self._subcontainer,
position=(h, v),
@@ -597,9 +582,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/iconpicker.py b/assets/src/ba_data/python/bastd/ui/iconpicker.py
index e80708bb..1d1820f4 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
@@ -46,18 +28,19 @@ class IconPicker(popup.PopupWindow):
tint2_color: Sequence[float] = (1.0, 1.0, 1.0),
selected_icon: str = None):
# pylint: disable=too-many-locals
- from ba.internal import get_purchased_icons
del parent # unused here
del tint_color # unused_here
del tint2_color # unused here
+ uiscale = ba.app.ui.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
- self._icons = [ba.charstr(ba.SpecialChar.LOGO)] + get_purchased_icons()
+ self._icons = [ba.charstr(ba.SpecialChar.LOGO)
+ ] + ba.app.accounts.get_purchased_icons()
count = len(self._icons)
columns = 4
rows = int(math.ceil(float(count) / columns))
@@ -69,7 +52,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
@@ -151,15 +135,15 @@ class IconPicker(popup.PopupWindow):
ba.widget(edit=btn, show_buffer_top=30, show_buffer_bottom=30)
def _on_store_press(self) -> None:
- 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._transition_out()
- browser.StoreBrowserWindow(modal=True,
- show_tab='icons',
- origin_widget=self._get_more_icons_button)
+ StoreBrowserWindow(modal=True,
+ show_tab=StoreBrowserWindow.TabID.ICONS,
+ origin_widget=self._get_more_icons_button)
def _select_icon(self, icon: str) -> None:
if self._delegate is not None:
diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py
index 724113d3..c75caeca 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
@@ -36,12 +18,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),
@@ -99,8 +81,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,7 +294,7 @@ class KioskWindow(ba.Window):
self._b4 = self._b5 = self._b6 = None
self._b7: Optional[ba.Widget]
- if bool(False):
+ if ba.app.arcade_mode:
self._b7 = ba.buttonwidget(
parent=self._root_widget,
autoselect=True,
@@ -319,10 +302,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 ba.app.small_ui 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)
@@ -336,10 +316,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.ui.window_states.get(type(self))
sel: Optional[ba.Widget]
if sel_name == 'b1':
sel = self._b1
@@ -378,7 +355,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[type(self)] = sel_name
def _update(self) -> None:
# Kiosk-mode is designed to be used signed-out... try for force
@@ -389,20 +366,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 +389,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 +397,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 +409,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 +421,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,
@@ -468,4 +445,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/__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 a1aecb5a..f299f5ff 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
@@ -44,7 +26,6 @@ class LeagueRankButton:
color: Tuple[float, float, float] = None,
textcolor: Tuple[float, float, float] = None,
smooth_update_delay: float = None):
- from ba.internal import get_cached_league_rank_data
if on_activate_call is None:
on_activate_call = ba.WeakCall(self._default_on_activate_call)
self._on_activate_call = on_activate_call
@@ -125,7 +106,7 @@ class LeagueRankButton:
self._update()
# If we've got cached power-ranking data already, apply it.
- data = get_cached_league_rank_data()
+ data = ba.app.accounts.get_cached_league_rank_data()
if data is not None:
self._update_for_league_rank_data(data)
@@ -227,14 +208,13 @@ 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,
Any]]) -> None:
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
- from ba.internal import get_league_rank_points
# If our button has died, ignore.
if not self._button:
@@ -268,7 +248,7 @@ class LeagueRankButton:
self._percent = self._rank = None
status_text = '-'
else:
- our_points = get_league_rank_points(data)
+ our_points = ba.app.accounts.get_league_rank_points(data)
progress = float(our_points) / data['scores'][-1][1]
self._percent = int(progress * 100.0)
self._rank = None
@@ -285,7 +265,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,24 +306,28 @@ 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(
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)
def _on_power_ranking_query_response(
self, data: Optional[Dict[str, Any]]) -> None:
- from ba.internal import cache_league_rank_data
self._doing_power_ranking_query = False
- cache_league_rank_data(data)
+ ba.app.accounts.cache_league_rank_data(data)
self._update_for_league_rank_data(data)
def _update(self) -> None:
@@ -369,8 +353,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/league/rankwindow.py b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py
index 066adfc7..0ee0c9db 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
@@ -40,8 +22,6 @@ class LeagueRankWindow(ba.Window):
transition: str = 'in_right',
modal: bool = False,
origin_widget: ba.Widget = None):
- from ba.internal import get_cached_league_rank_data
- from ba.deprecated import get_resource
ba.set_analytics_screen('League Rank Window')
self._league_rank_data: Optional[Dict[str, Any]] = None
@@ -57,13 +37,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.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
+ 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
+ self._rdict = ba.app.lang.get_resource(self._r)
+ top_extra = 20 if uiscale is ba.UIScale.SMALL else 0
self._league_url_arg = ''
@@ -72,17 +53,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,
@@ -98,7 +79,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')
@@ -106,7 +87,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))
@@ -143,7 +124,7 @@ class LeagueRankWindow(ba.Window):
self._restore_state()
# if we've got cached power-ranking data already, display it
- info = get_cached_league_rank_data()
+ info = ba.app.accounts.get_cached_league_rank_data()
if info is not None:
self._update_for_league_rank_data(info)
@@ -212,11 +193,10 @@ class LeagueRankWindow(ba.Window):
def _on_power_ranking_query_response(
self, data: Optional[Dict[str, Any]]) -> None:
- from ba.internal import cache_league_rank_data
self._doing_power_ranking_query = False
# important: *only* cache this if we requested the current season..
if data is not None and data.get('s', None) is None:
- cache_league_rank_data(data)
+ ba.app.accounts.cache_league_rank_data(data)
# always store a copy locally though (even for other seasons)
self._league_rank_data = copy.deepcopy(data)
self._update_for_league_rank_data(data)
@@ -259,7 +239,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
@@ -612,9 +592,9 @@ class LeagueRankWindow(ba.Window):
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
- from ba.internal import get_league_rank_points
if not self._root_widget:
return
+ accounts = ba.app.accounts
in_top = (data is not None and data['rank'] is not None)
eq_text = self._rdict.powerRankingPointsEqualsText
pts_txt = self._rdict.powerRankingPointsText
@@ -640,7 +620,7 @@ class LeagueRankWindow(ba.Window):
finished_season_unranked = True
self._can_do_more_button = False
else:
- our_points = get_league_rank_points(data)
+ our_points = accounts.get_league_rank_points(data)
progress = float(our_points) / max(1,
data['scores'][-1][1])
status_text = str(int(progress * 100.0)) + '%'
@@ -651,7 +631,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 = ''
@@ -826,7 +806,7 @@ class LeagueRankWindow(ba.Window):
# for the achievement value, use the number they gave us for
# non-current seasons; otherwise calc our own
total_ach_value = 0
- for ach in ba.app.achievements:
+ for ach in ba.app.ach.achievements:
if ach.complete:
total_ach_value += ach.power_ranking_value
if self._season != 'a' and not self._is_current_season:
@@ -838,8 +818,10 @@ class LeagueRankWindow(ba.Window):
('+ ' +
pts_txt.replace('${NUMBER}', str(total_ach_value))))
- total_trophies_count = (get_league_rank_points(data, 'trophyCount'))
- total_trophies_value = (get_league_rank_points(data, 'trophies'))
+ total_trophies_count = (accounts.get_league_rank_points(
+ data, 'trophyCount'))
+ total_trophies_value = (accounts.get_league_rank_points(
+ data, 'trophies'))
ba.buttonwidget(edit=self._power_ranking_trophies_button,
label=('' if data is None else
(str(total_trophies_count) + ' ')) +
@@ -849,9 +831,10 @@ class LeagueRankWindow(ba.Window):
text='-' if data is None else
('+ ' + pts_txt.replace('${NUMBER}', str(total_trophies_value))))
- ba.textwidget(edit=self._power_ranking_total_text,
- text='-' if data is None else eq_text.replace(
- '${NUMBER}', str(get_league_rank_points(data))))
+ ba.textwidget(
+ edit=self._power_ranking_total_text,
+ text='-' if data is None else eq_text.replace(
+ '${NUMBER}', str(accounts.get_league_rank_points(data))))
for widget in self._power_ranking_score_widgets:
widget.delete()
self._power_ranking_score_widgets = []
@@ -929,10 +912,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 c3d9fd54..c82c7eb1 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
@@ -37,12 +19,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.
@@ -51,7 +38,11 @@ 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
+ # Grab this stuff in case it changes.
+ self._is_demo = ba.app.demo_mode
+ self._is_arcade = ba.app.arcade_mode
+ self._is_iircade = ba.app.iircade_mode
+
self._tdelay = 0.0
self._t_delay_inc = 0.02
self._t_delay_play = 1.7
@@ -68,6 +59,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()
@@ -84,6 +76,22 @@ class MainMenuWindow(ba.Window):
repeat=True,
timetype=ba.TimeType.REAL)
+ @staticmethod
+ def _preload_modules() -> None:
+ """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
+ 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,18 +107,18 @@ 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,
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(
@@ -125,7 +133,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()
@@ -149,7 +157,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.
@@ -166,15 +174,15 @@ class MainMenuWindow(ba.Window):
self._r = 'mainMenu'
app = ba.app
- self._have_quit_button = (app.interface_type == 'large'
+ self._have_quit_button = (app.ui.uiscale is ba.UIScale.LARGE
or (app.platform == 'windows'
and app.subplatform == 'oculus'))
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 or self._is_iircade))
self._input_device = input_device = _ba.get_ui_input_device()
self._input_player = input_device.player if input_device else None
@@ -267,8 +275,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.ui.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,
@@ -323,7 +332,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)
@@ -335,12 +344,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.ui.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
@@ -429,14 +439,17 @@ class MainMenuWindow(ba.Window):
account_type_icon_color = (1.0, 1.0, 1.0)
account_type_call = self._show_account_window
account_type_enable_button_sound = True
- b_count = 4 # play, help, credits, settings
+ b_count = 3 # play, help, credits
+ if self._have_settings_button:
+ b_count += 1
if enable_account_button:
b_count += 1
if self._have_quit_button:
b_count += 1
if self._have_store_button:
b_count += 1
- if ba.app.small_ui:
+ uiscale = ba.app.ui.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
@@ -445,7 +458,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
@@ -476,7 +489,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(
@@ -488,12 +501,15 @@ 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:
self._demo_menu_button = None
- foof = (-1 if ba.app.small_ui else 1 if ba.app.med_ui else 3)
+ 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]
v = v + foof
gather_delay = 0.0 if self._t_delay_play == 0.0 else max(
@@ -673,15 +689,15 @@ class MainMenuWindow(ba.Window):
if (not isinstance(cme, dict) or 'label' not in cme
or not isinstance(cme['label'], (str, ba.Lstr))
or 'call' not in cme or not callable(cme['call'])):
- raise Exception('invalid custom menu entry: ' +
- str(cme))
+ raise ValueError('invalid custom menu entry: ' +
+ 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:
+ if (self._is_demo or self._is_arcade) and self._input_player:
self._height -= 40
if not self._have_settings_button:
self._height -= 50
@@ -689,10 +705,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.ui.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
@@ -708,7 +726,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,
@@ -738,10 +756,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'])
@@ -757,7 +772,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,
@@ -799,6 +814,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,
@@ -807,68 +826,69 @@ 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(
- 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 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(
- 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
- 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(
- 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
- 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()
@@ -877,7 +897,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:
@@ -889,28 +909,31 @@ 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(
- 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 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(
- 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 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(
- 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()
@@ -927,28 +950,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
@@ -956,7 +979,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'
@@ -988,30 +1011,32 @@ 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.selecting_private_party_playlist = False
+ 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 431a123a..d5ad875a 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
@@ -26,6 +8,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
@@ -35,20 +19,21 @@ 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
self._target_text = textwidget
self._width = 700
self._height = 400
- top_extra = 20 if ba.app.small_ui else 0
+ 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'),
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),
@@ -65,7 +50,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')
@@ -83,19 +68,44 @@ class OnScreenKeyboardWindow(ba.Window):
force_internal_editing=True,
always_show_carat=True)
- self._shift_button = None
- self._num_mode_button = None
- self._char_keys: List[ba.Widget] = []
- self._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')
@@ -106,16 +116,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),
@@ -123,7 +129,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',
@@ -147,17 +153,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=ba.charstr(ba.SpecialChar.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:
@@ -174,22 +184,52 @@ 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=charstr(SpCh.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),
- 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, ' '))
- ba.widget(edit=btn1, right_widget=btn2)
+ 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, ' '))
+
+ # Show change instructions only if we have more than one
+ # keyboard option.
+ if (ba.app.meta.metascan is not None
+ and len(ba.app.meta.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)
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,
@@ -197,30 +237,35 @@ class OnScreenKeyboardWindow(ba.Window):
self._refresh()
+ def _get_keyboard(self) -> ba.Keyboard:
+ assert ba.app.meta.metascan is not None
+ classname = ba.app.meta.metascan.keyboards[self._keyboard_index]
+ kbclass = ba.getclass(classname, ba.Keyboard)
+ return kbclass()
+
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,
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)
- elif self._mode == 'num':
- chars = [
- '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '/',
- ':', ';', '(', ')', '$', '&', '@', '"', '.', ',', '?', '!',
- '\'', '_'
- ]
+ ba.buttonwidget(edit=self._emoji_button,
+ color=self._key_color_dark,
+ label=charstr(SpCh.LOGO_FLAT),
+ 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='',
@@ -228,13 +273,29 @@ 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._next_mode)
for i, btn in enumerate(self._char_keys):
assert chars is not None
+ have_char = True
+ if i >= len(chars):
+ # No such char.
+ have_char = False
+ pagename = self._mode
+ ba.print_error(
+ f'Size of page "{pagename}" of keyboard'
+ f' "{self._keyboard.name}" is incorrect:'
+ f' {len(chars)} != {len(self._chars)}'
+ f' (size of default "normal" page)',
+ once=True)
ba.buttonwidget(edit=btn,
- label=chars[i],
- on_activate_call=ba.Call(self._type_char,
- chars[i]))
+ label=chars[i] if have_char else ' ',
+ on_activate_call=ba.Call(
+ self._type_char,
+ chars[i] if have_char else ' '))
def _null_press(self) -> None:
ba.playsound(self._click_sound)
@@ -249,12 +310,36 @@ class OnScreenKeyboardWindow(ba.Window):
self._mode = 'num'
self._refresh()
+ def _next_mode(self) -> None:
+ ba.playsound(self._click_sound)
+ self._mode_index = (self._mode_index + 1) % len(self._modes)
+ self._mode = self._modes[self._mode_index]
+ self._refresh()
+
+ def _next_keyboard(self) -> None:
+ assert ba.app.meta.metascan is not None
+ self._keyboard_index = (self._keyboard_index + 1) % len(
+ ba.app.meta.metascan.keyboards)
+ self._load_keyboard()
+ if len(ba.app.meta.metascan.keyboards) < 2:
+ ba.playsound(ba.getsound('error'))
+ ba.screenmessage(ba.Lstr(resource='keyboardNoOthersAvailableText'),
+ color=(1, 0, 0))
+ else:
+ ba.screenmessage(ba.Lstr(resource='keyboardSwitchText',
+ subs=[('${NAME}', self._keyboard.name)]),
+ color=(0, 1, 0))
+
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:
@@ -266,13 +351,23 @@ class OnScreenKeyboardWindow(ba.Window):
def _type_char(self, char: str) -> None:
ba.playsound(self._click_sound)
- # operate in unicode so we don't do anything funky like chop utf-8
- # chars in half
+ 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))
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 not self._double_press_shift:
self._mode = 'normal'
self._refresh()
diff --git a/assets/src/ba_data/python/bastd/ui/party.py b/assets/src/ba_data/python/bastd/ui/party.py
index a60787ab..99fb7abd 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
@@ -47,8 +29,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.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(
size=(self._width, self._height),
transition='in_scale',
@@ -56,9 +39,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,
@@ -87,7 +71,7 @@ class PartyWindow(ba.Window):
info = _ba.get_connection_to_host_info()
if info.get('name', '') != '':
- title = info['name']
+ title = ba.Lstr(value=info['name'])
else:
title = ba.Lstr(resource=self._r + '.titleText')
@@ -117,7 +101,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(
@@ -198,9 +184,11 @@ class PartyWindow(ba.Window):
def _on_menu_button_press(self) -> None:
is_muted = ba.app.config.resolve('Chat Muted')
+ uiscale = ba.app.ui.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(
@@ -281,10 +269,10 @@ 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')
+ 'Error calcing client name str.')
p_str = '???'
widget = ba.textwidget(parent=self._root_widget,
@@ -400,9 +388,11 @@ class PartyWindow(ba.Window):
14248):
return
kick_str = ba.Lstr(resource='kickVoteText')
+ uiscale = ba.app.ui.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',
@@ -464,7 +454,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/assets/src/ba_data/python/bastd/ui/partyqueue.py b/assets/src/ba_data/python/bastd/ui/partyqueue.py
index 582e9410..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
@@ -187,7 +169,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
@@ -223,11 +205,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.ui.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,
@@ -272,14 +256,14 @@ 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
})
_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)"""
@@ -374,8 +358,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/assets/src/ba_data/python/bastd/ui/play.py b/assets/src/ba_data/python/bastd/ui/play.py
index 2ca24f32..620b7a04 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
@@ -39,10 +21,20 @@ class PlayWindow(ba.Window):
origin_widget: ba.Widget = None):
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
- new_style = True
- width = 1000 if ba.app.small_ui else 800
- x_offs = 100 if ba.app.small_ui else 0
- height = 550 if new_style else 400
+ 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()
+
+ # We can currently be used either for main menu duty or for selecting
+ # playlists (should make this more elegant/general).
+ self._is_main_menu = not ba.app.ui.selecting_private_party_playlist
+
+ 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
button_width = 400
scale_origin: Optional[Tuple[float, float]]
@@ -61,14 +53,12 @@ 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,
- stack_offset=((0, 0) if new_style else (
- 10, 7)) if ba.app.small_ui else (0, 0)))
+ scale=(1.6 if uiscale is ba.UIScale.SMALL else
+ 0.9 if uiscale is ba.UIScale.MEDIUM else 0.8),
+ stack_offset=(0, 0) 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
- (55, height - 92),
+ position=(55 + x_offs, height - 132),
size=(120, 60),
scale=1.1,
text_res_scale=1.5,
@@ -77,32 +67,37 @@ class PlayWindow(ba.Window):
label=ba.Lstr(resource='backText'),
button_type='back')
- txt = ba.textwidget(parent=self._root_widget,
- position=(width * 0.5,
- height - (101 if new_style else 61)),
- size=(0, 0),
- text=ba.Lstr(resource=self._r + '.titleText'),
- scale=1.7,
- res_scale=2.0,
- maxwidth=400,
- color=ba.app.heading_color,
- h_align='center',
- v_align='center')
+ txt = ba.textwidget(
+ parent=self._root_widget,
+ position=(width * 0.5, height - 101),
+ # position=(width * 0.5, height -
+ # (101 if main_menu else 61)),
+ size=(0, 0),
+ text=ba.Lstr(resource=(
+ self._r +
+ '.titleText') if self._is_main_menu else 'playlistsText'),
+ scale=1.7,
+ res_scale=2.0,
+ maxwidth=400,
+ color=ba.app.ui.heading_color,
+ h_align='center',
+ v_align='center')
ba.buttonwidget(edit=btn,
button_type='backSmall',
size=(60, 60),
label=ba.charstr(ba.SpecialChar.BACK))
- if ba.app.toolbars and ba.app.small_ui:
+ 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 = height - (110 if self._is_main_menu else 90)
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
- hoffs = x_offs + 80 if new_style else 0
- scl = 1.13 if new_style else 0.68
+ v -= 280 if self._is_main_menu else 180
+ v += (30
+ if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL else 0)
+ hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
+ scl = 1.13 if self._is_main_menu else 0.68
self._lineup_tex = ba.gettexture('playerLineup')
angry_computer_transparent_model = ba.getmodel(
@@ -117,93 +112,102 @@ class PlayWindow(ba.Window):
'playerLineup4Transparent')
self._eyes_model = ba.getmodel('plasticEyesTransparent')
- self._coop_button = btn = ba.buttonwidget(
- parent=self._root_widget,
- position=(hoffs, v + (scl * 15 if new_style else 0)),
- size=(scl * button_width, scl * (300 if new_style else 360)),
- extra_touch_border_scale=0.1,
- autoselect=True,
- label='',
- button_type='square',
- text_scale=1.13,
- on_activate_call=self._coop)
+ self._coop_button: Optional[ba.Widget] = None
- if ba.app.toolbars and ba.app.small_ui:
- ba.widget(edit=btn,
- left_widget=_ba.get_special_widget('back_button'))
- ba.widget(edit=btn,
- up_widget=_ba.get_special_widget('account_button'))
- ba.widget(edit=btn,
- down_widget=_ba.get_special_widget('settings_button'))
+ # Only show coop button in main-menu variant.
+ if self._is_main_menu:
+ self._coop_button = btn = ba.buttonwidget(
+ parent=self._root_widget,
+ position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
+ size=(scl * button_width,
+ scl * (300 if self._is_main_menu else 360)),
+ extra_touch_border_scale=0.1,
+ autoselect=True,
+ label='',
+ button_type='square',
+ text_scale=1.13,
+ on_activate_call=self._coop)
- self._draw_dude(0,
- btn,
- hoffs,
- v,
- scl,
- position=(140, 30),
- color=(0.72, 0.4, 1.0))
- self._draw_dude(1,
- btn,
- hoffs,
- v,
- scl,
- position=(185, 53),
- color=(0.71, 0.5, 1.0))
- self._draw_dude(2,
- btn,
- hoffs,
- v,
- scl,
- position=(220, 27),
- color=(0.67, 0.44, 1.0))
- self._draw_dude(3,
- btn,
- hoffs,
- v,
- scl,
- position=(255, 57),
- color=(0.7, 0.3, 1.0))
- ba.imagewidget(parent=self._root_widget,
- draw_controller=btn,
- position=(hoffs + scl * 230, v + scl * 153),
- size=(scl * 115, scl * 115),
- texture=self._lineup_tex,
- model_transparent=angry_computer_transparent_model)
+ 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,
+ up_widget=_ba.get_special_widget('account_button'))
+ ba.widget(
+ edit=btn,
+ down_widget=_ba.get_special_widget('settings_button'))
- ba.textwidget(parent=self._root_widget,
- draw_controller=btn,
- position=(hoffs + scl * (-10), v + scl * 95),
- size=(scl * button_width, scl * 50),
- text=ba.Lstr(resource='playModes.singlePlayerCoopText',
- fallback_resource='playModes.coopText'),
- maxwidth=scl * button_width * 0.7,
- res_scale=1.5,
- h_align='center',
- v_align='center',
- color=(0.7, 0.9, 0.7, 1.0),
- scale=scl * 2.3)
+ self._draw_dude(0,
+ btn,
+ hoffs,
+ v,
+ scl,
+ position=(140, 30),
+ color=(0.72, 0.4, 1.0))
+ self._draw_dude(1,
+ btn,
+ hoffs,
+ v,
+ scl,
+ position=(185, 53),
+ color=(0.71, 0.5, 1.0))
+ self._draw_dude(2,
+ btn,
+ hoffs,
+ v,
+ scl,
+ position=(220, 27),
+ color=(0.67, 0.44, 1.0))
+ self._draw_dude(3,
+ btn,
+ hoffs,
+ v,
+ scl,
+ position=(255, 57),
+ color=(0.7, 0.3, 1.0))
+ ba.imagewidget(parent=self._root_widget,
+ draw_controller=btn,
+ position=(hoffs + scl * 230, v + scl * 153),
+ size=(scl * 115, scl * 115),
+ texture=self._lineup_tex,
+ model_transparent=angry_computer_transparent_model)
- ba.textwidget(parent=self._root_widget,
- draw_controller=btn,
- position=(hoffs + scl * (-10), v + (scl * 54)),
- size=(scl * button_width, scl * 30),
- text=ba.Lstr(resource=self._r + '.oneToFourPlayersText'),
- h_align='center',
- v_align='center',
- scale=0.83 * scl,
- flatness=1.0,
- maxwidth=scl * button_width * 0.7,
- color=clr)
+ ba.textwidget(parent=self._root_widget,
+ draw_controller=btn,
+ position=(hoffs + scl * (-10), v + scl * 95),
+ size=(scl * button_width, scl * 50),
+ text=ba.Lstr(
+ resource='playModes.singlePlayerCoopText',
+ fallback_resource='playModes.coopText'),
+ maxwidth=scl * button_width * 0.7,
+ res_scale=1.5,
+ h_align='center',
+ v_align='center',
+ color=(0.7, 0.9, 0.7, 1.0),
+ scale=scl * 2.3)
- scl = 0.5 if new_style else 0.68
- hoffs += 440 if new_style else 260
- v += 180 if new_style else 0
+ ba.textwidget(parent=self._root_widget,
+ draw_controller=btn,
+ position=(hoffs + scl * (-10), v + (scl * 54)),
+ size=(scl * button_width, scl * 30),
+ text=ba.Lstr(resource=self._r +
+ '.oneToFourPlayersText'),
+ h_align='center',
+ v_align='center',
+ scale=0.83 * scl,
+ flatness=1.0,
+ maxwidth=scl * button_width * 0.7,
+ color=clr)
+
+ scl = 0.5 if self._is_main_menu else 0.68
+ hoffs += 440 if self._is_main_menu else 216
+ v += 180 if self._is_main_menu else -68
self._teams_button = btn = ba.buttonwidget(
parent=self._root_widget,
- position=(hoffs, v + (scl * 15 if new_style else 0)),
- size=(scl * button_width, scl * (300 if new_style else 360)),
+ position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
+ size=(scl * button_width,
+ scl * (300 if self._is_main_menu else 360)),
extra_touch_border_scale=0.1,
autoselect=True,
label='',
@@ -211,7 +215,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'))
@@ -302,12 +306,13 @@ class PlayWindow(ba.Window):
maxwidth=scl * button_width * 0.7,
color=clr)
- hoffs += 0 if new_style else 260
- v -= 155 if new_style else 0
+ hoffs += 0 if self._is_main_menu else 300
+ v -= 155 if self._is_main_menu else 0
self._free_for_all_button = btn = ba.buttonwidget(
parent=self._root_widget,
- position=(hoffs, v + (scl * 15 if new_style else 0)),
- size=(scl * button_width, scl * (300 if new_style else 360)),
+ position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
+ size=(scl * button_width,
+ scl * (300 if self._is_main_menu else 360)),
extra_touch_border_scale=0.1,
autoselect=True,
label='',
@@ -397,57 +402,78 @@ class PlayWindow(ba.Window):
maxwidth=scl * button_width * 0.7,
color=clr)
- if ba.app.toolbars and ba.app.small_ui:
+ 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,
- selected_child=self._coop_button)
+ selected_child=self._coop_button
+ if self._is_main_menu else self._teams_button)
else:
ba.buttonwidget(edit=back_button, on_activate_call=self._back)
ba.containerwidget(edit=self._root_widget,
cancel_button=back_button,
- selected_child=self._coop_button)
+ selected_child=self._coop_button
+ if self._is_main_menu else self._teams_button)
self._restore_state()
+ @staticmethod
+ def _preload_modules() -> None:
+ """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
+ import bastd.ui.playlist.browser as _unused4
+
def _back(self) -> None:
# pylint: disable=cyclic-import
- from bastd.ui import mainmenu
- self._save_state()
- ba.app.main_menu_window = (mainmenu.MainMenuWindow(
- transition='in_left').get_root_widget())
- ba.containerwidget(edit=self._root_widget,
- transition=self._transition_out)
+ if self._is_main_menu:
+ from bastd.ui.mainmenu import MainMenuWindow
+ self._save_state()
+ ba.app.ui.set_main_menu_window(
+ MainMenuWindow(transition='in_left').get_root_widget())
+ ba.containerwidget(edit=self._root_widget,
+ transition=self._transition_out)
+ else:
+ from bastd.ui.gather import GatherWindow
+ self._save_state()
+ ba.app.ui.set_main_menu_window(
+ GatherWindow(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(
- 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 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(
- 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 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(
- 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],
@@ -531,34 +557,32 @@ class PlayWindow(ba.Window):
sel = self._root_widget.get_selected_child()
if sel == self._teams_button:
sel_name = 'Team Games'
- elif sel == self._coop_button:
+ elif self._coop_button is not None and sel == self._coop_button:
sel_name = 'Co-op Games'
elif sel == self._free_for_all_button:
sel_name = 'Free-for-All Games'
elif sel == self._back_button:
sel_name = 'Back'
else:
- raise Exception('unrecognized selected widget')
- ba.app.window_states[self.__class__.__name__] = sel_name
+ raise ValueError(f'unrecognized selection {sel}')
+ ba.app.ui.window_states[type(self)] = 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.ui.window_states.get(type(self))
if sel_name == 'Team Games':
sel = self._teams_button
- elif sel_name == 'Co-op Games':
+ elif sel_name == 'Co-op Games' and self._coop_button is not None:
sel = self._coop_button
elif sel_name == 'Free-for-All Games':
sel = self._free_for_all_button
elif sel_name == 'Back':
sel = self._back_button
else:
- sel = self._coop_button
+ sel = (self._coop_button if self._coop_button is not None else
+ self._teams_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/__init__.py b/assets/src/ba_data/python/bastd/ui/playlist/__init__.py
index e232156f..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
@@ -38,6 +20,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 +30,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,9 +41,10 @@ class PlaylistTypeVars:
resource='playModes.freeForAllText',
fallback_resource='freeForAllText')
self.sessiontype = ba.FreeForAllSession
+
else:
- raise Exception('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/playlist/addgame.py b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py
index f60827ad..af51c57e 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
@@ -40,18 +22,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.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
+ 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,
@@ -73,7 +57,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'))
@@ -83,7 +67,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
@@ -136,16 +120,17 @@ class PlaylistAddGameWindow(ba.Window):
self._refresh()
def _refresh(self, select_get_more_games_button: bool = False) -> None:
- from ba.internal import get_game_types
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(
- self._editcontroller.get_session_type())
+ gt for gt in ba.app.meta.get_game_types() if
+ gt.supports_session_type(self._editcontroller.get_session_type())
]
# Sort in the current language.
@@ -189,15 +174,15 @@ class PlaylistAddGameWindow(ba.Window):
visible_child=self._get_more_games_button)
def _on_get_more_games_press(self) -> None:
- 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
- browser.StoreBrowserWindow(modal=True,
- show_tab='minigames',
- on_close_call=self._on_store_close,
- origin_widget=self._get_more_games_button)
+ StoreBrowserWindow(modal=True,
+ show_tab=StoreBrowserWindow.TabID.MINIGAMES,
+ on_close_call=self._on_store_close,
+ origin_widget=self._get_more_games_button)
def _on_store_close(self) -> None:
self._refresh(select_get_more_games_button=True)
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 b3138e4d..0a3c7ef9 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
@@ -42,7 +24,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]]
@@ -56,14 +38,14 @@ 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 Exception(f'invalid sessiontype: {sessiontype}')
- self._pvars = playlist.PlaylistTypeVars(sessiontype)
+ raise TypeError(f'Invalid sessiontype: {sessiontype}.')
+ self._pvars = PlaylistTypeVars(sessiontype)
self._sessiontype = sessiontype
@@ -71,152 +53,28 @@ class PlaylistBrowserWindow(ba.Window):
self._sub_width: Optional[float] = None
self._sub_height: Optional[float] = None
- # 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',
- 'playlistName':
- ba.Lstr(resource='singleGamePlaylistNameText'
- ).evaluate().replace(
- '${GAME}',
- 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': 'Crag Castle'}
- }
- ]
- })
- _ba.add_transaction({
- 'type': 'ADD_PLAYLIST',
- 'playlistType': 'Team Tournament',
- 'playlistName':
- ba.Lstr(
- resource='singleGamePlaylistNameText'
- ).evaluate().replace(
- '${GAME}',
- 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': '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}
- }
- ]
- })
- _ba.add_transaction({
- 'type': 'ADD_PLAYLIST',
- 'playlistType': 'Team Tournament',
- 'playlistName':
- 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_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',
- '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.add_transaction({
- 'type': 'SET_MISC_VAL',
- 'name': 'madeStandardPlaylists',
- 'value': True
- })
- # yapf: enable
- _ba.run_transactions()
+ self._ensure_standard_playlists_exist()
# 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
- self._height = (480
- if ba.app.small_ui else 510 if ba.app.med_ui else 580)
+ 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
+ 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,
@@ -236,10 +94,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 ba.app.small_ui 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,
@@ -248,7 +106,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.ui.use_toolbars:
self._back_button.delete()
self._back_button = None
ba.containerwidget(edit=self._root_widget,
@@ -257,8 +115,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 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.ui.use_toolbars else 136))
self._scrollwidget = ba.scrollwidget(
parent=self._root_widget,
highlight=False,
@@ -270,12 +129,157 @@ 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 _ensure_standard_playlists_exist(self) -> None:
+ # 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):
+ _ba.add_transaction({
+ 'type':
+ 'ADD_PLAYLIST',
+ 'playlistType':
+ 'Free-for-All',
+ 'playlistName':
+ ba.Lstr(resource='singleGamePlaylistNameText'
+ ).evaluate().replace(
+ '${GAME}',
+ 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': 'Crag Castle'
+ }
+ },
+ ]
+ })
+ _ba.add_transaction({
+ 'type':
+ 'ADD_PLAYLIST',
+ 'playlistType':
+ 'Team Tournament',
+ 'playlistName':
+ ba.Lstr(
+ resource='singleGamePlaylistNameText'
+ ).evaluate().replace(
+ '${GAME}',
+ 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': '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
+ }
+ },
+ ]
+ })
+ _ba.add_transaction({
+ 'type':
+ 'ADD_PLAYLIST',
+ 'playlistType':
+ 'Team Tournament',
+ 'playlistName':
+ 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_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',
+ '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.add_transaction({
+ 'type': 'SET_MISC_VAL',
+ 'name': 'madeStandardPlaylists',
+ 'value': True
+ })
+ _ba.run_transactions()
def _refresh(self) -> None:
# FIXME: Should tidy this up.
@@ -283,26 +287,25 @@ class PlaylistBrowserWindow(ba.Window):
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
# pylint: disable=too-many-nested-blocks
- from ba.internal import (get_map_class,
- get_default_free_for_all_playlist,
- get_default_teams_playlist, filter_playlist)
+ from efro.util import asserttype
+ from ba.internal import get_map_class, filter_playlist
if not self._root_widget:
return
if self._subcontainer is not None:
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]
- 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)
@@ -333,12 +336,12 @@ 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')
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')
@@ -347,6 +350,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.ui.uiscale
for y in range(rows):
for x in range(columns):
name = items[index][0]
@@ -361,11 +365,13 @@ 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.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 and ba.app.small_ui:
+ if (x == columns - 1 and ba.app.ui.use_toolbars
+ and uiscale is ba.UIScale.SMALL):
ba.widget(
edit=btn,
right_widget=_ba.get_special_widget('party_button'))
@@ -410,21 +416,15 @@ class PlaylistBrowserWindow(ba.Window):
map_textures = []
map_texture_entries = []
if name == '__default__':
- if self._sessiontype is ba.FreeForAllSession:
- playlist = (get_default_free_for_all_playlist())
- elif self._sessiontype is ba.DualTeamSession:
- playlist = get_default_teams_playlist()
- else:
- raise Exception('unrecognized session-type: ' +
- str(self._sessiontype))
+ playlist = self._pvars.get_default_list_call()
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,
@@ -435,7 +435,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()
@@ -507,7 +507,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 +563,40 @@ 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(
- 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
- 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,8 +606,8 @@ class PlaylistBrowserWindow(ba.Window):
self._save_state()
ba.containerwidget(edit=self._root_widget,
transition=self._transition_out)
- ba.app.main_menu_window = (play.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:
@@ -626,16 +623,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[type(self)] = 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.ui.window_states.get(type(self))
if sel_name == 'Back':
sel = self._back_button
elif sel_name == 'Scroll':
@@ -649,4 +643,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/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py
index dda12b80..4ee5b297 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
@@ -59,18 +41,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.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
+ 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,
@@ -88,7 +72,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')
@@ -105,7 +89,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(
@@ -225,15 +210,14 @@ 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
- 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
@@ -242,7 +226,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'
@@ -269,8 +253,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
self._update()
def _update(self) -> None:
- from ba.internal import have_pro_options
- have = have_pro_options()
+ have = ba.app.accounts.have_pro_options()
for lock in self._lock_images:
ba.imagewidget(edit=lock, opacity=0.0 if have else 1.0)
@@ -285,9 +268,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
@@ -300,7 +284,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)
@@ -314,15 +298,13 @@ 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.
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
@@ -336,7 +318,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
@@ -399,11 +381,10 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
def _new_playlist(self) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui.playlist import editcontroller
- from bastd.ui import purchase
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.playlist.editcontroller import PlaylistEditController
+ from bastd.ui.purchase import PurchaseWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
# Clamp at our max playlist number.
@@ -419,16 +400,15 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
self._save_playlist_selection()
# Kick off the edit UI.
- editcontroller.PlaylistEditController(sessiontype=self._sessiontype)
+ PlaylistEditController(sessiontype=self._sessiontype)
ba.containerwidget(edit=self._root_widget, transition='out_left')
def _edit_playlist(self) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui.playlist import editcontroller
- from bastd.ui import purchase
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.playlist.editcontroller import PlaylistEditController
+ from bastd.ui.purchase import PurchaseWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
if self._selected_playlist_name is None:
return
@@ -438,7 +418,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
'.cantEditDefaultText'))
return
self._save_playlist_selection()
- editcontroller.PlaylistEditController(
+ PlaylistEditController(
existing_playlist_name=self._selected_playlist_name,
sessiontype=self._sessiontype)
ba.containerwidget(edit=self._root_widget, transition='out_left')
@@ -491,10 +471,9 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
def _share_playlist(self) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui import purchase
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.purchase import PurchaseWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
# Gotta be signed in for this to work.
@@ -527,11 +506,10 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
def _delete_playlist(self) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui import purchase
- from bastd.ui import confirm
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.purchase import PurchaseWindow
+ from bastd.ui.confirm import ConfirmWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
if self._selected_playlist_name is None:
@@ -541,7 +519,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
ba.screenmessage(
ba.Lstr(resource=self._r + '.cantDeleteDefaultText'))
else:
- confirm.ConfirmWindow(
+ ConfirmWindow(
ba.Lstr(resource=self._r + '.deleteConfirmText',
subs=[('${LIST}', self._selected_playlist_name)]),
self._do_delete_playlist, 450, 150)
@@ -555,10 +533,9 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
def _duplicate_playlist(self) -> None:
# pylint: disable=too-many-branches
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui import purchase
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.purchase import PurchaseWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
if self._selected_playlist_name is None:
return
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..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,31 +1,13 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
from typing import TYPE_CHECKING, cast
-import _ba
import ba
+import _ba
if TYPE_CHECKING:
from typing import Optional, List
@@ -45,17 +27,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.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
+ 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),
@@ -74,7 +58,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'))
@@ -86,7 +70,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',
@@ -110,7 +94,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,
@@ -133,7 +117,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(
@@ -211,7 +196,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]:
@@ -243,29 +230,32 @@ 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
- self._editcontroller.set_name(
+ # Store list name then tell the session to perform an add.
+ 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(
+ # Store list name then tell the session to perform an add.
+ self._editcontroller.setname(
cast(str, ba.textwidget(query=self._text_field)))
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
@@ -283,6 +273,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 +282,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':
@@ -312,10 +303,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'))
@@ -326,6 +318,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 +329,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 +346,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..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
@@ -41,10 +23,10 @@ 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
- 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.
@@ -53,13 +35,13 @@ 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'
# 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 +49,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 +69,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
@@ -96,8 +78,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)"""
@@ -115,11 +98,11 @@ class PlaylistEditController:
"""(internal)"""
self._edit_ui_selection = selection
- def get_name(self) -> str:
+ def getname(self) -> str:
"""(internal)"""
return self._name
- def set_name(self, name: str) -> None:
+ def setname(self, name: str) -> None:
"""(internal)"""
self._name = name
@@ -149,10 +132,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."""
@@ -162,49 +145,48 @@ 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)"""
- 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],
- 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
- 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 +202,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 60fc3aa0..8533cc11 100644
--- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py
+++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py
@@ -1,24 +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.
-# -----------------------------------------------------------------------------
-"""Provides UI for editing a game in a playlist."""
+"""Provides UI for editing a game config."""
from __future__ import annotations
@@ -34,10 +16,10 @@ if TYPE_CHECKING:
class PlaylistEditGameWindow(ba.Window):
- """Window for editing a game in a playlist."""
+ """Window for editing a game config."""
def __init__(self,
- gameclass: Type[ba.GameActivity],
+ gametype: Type[ba.GameActivity],
sessiontype: Type[ba.Session],
config: Optional[Dict[str, Any]],
completion_call: Callable[[Optional[Dict[str, Any]]], Any],
@@ -49,7 +31,7 @@ class PlaylistEditGameWindow(ba.Window):
# pylint: disable=too-many-locals
from ba.internal import (get_unowned_maps, get_filtered_map_name,
get_map_class, get_map_display_string)
- self._gameclass = gameclass
+ self._gametype = gametype
self._sessiontype = sessiontype
# If we're within an editing session we get passed edit_info
@@ -67,12 +49,12 @@ class PlaylistEditGameWindow(ba.Window):
self._r = 'gameSettingsWindow'
- valid_maps = gameclass.get_supported_maps(sessiontype)
+ valid_maps = gametype.get_supported_maps(sessiontype)
if not valid_maps:
ba.screenmessage(ba.Lstr(resource='noValidMapsErrorText'))
raise Exception('No valid maps')
- self._settings_defs = gameclass.get_settings(sessiontype)
+ self._settings_defs = gametype.get_available_settings(sessiontype)
self._completion_call = completion_call
# To start with, pick a random map out of the ones we own.
@@ -97,7 +79,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']
@@ -106,9 +88,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.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
+ 460 if uiscale is ba.UIScale.MEDIUM else 550)
spacing = 52
y_extra = 15
y_extra2 = 21
@@ -118,13 +102,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,
@@ -149,15 +133,15 @@ 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)
ba.textwidget(parent=self._root_widget,
position=(-8, height - 70 + y_extra2),
size=(width, 25),
- text=gameclass.get_display_string(),
- color=ba.app.title_color,
+ text=gametype.get_display_string(),
+ color=ba.app.ui.title_color,
maxwidth=235,
scale=1.1,
h_align='center',
@@ -175,22 +159,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
@@ -239,52 +218,52 @@ 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):
+ for choice in setting.choices:
if len(choice) != 2:
- raise Exception(
+ raise ValueError(
"Expected 2-member tuples for 'choices'; got: " +
repr(choice))
if not isinstance(choice[0], str):
- raise Exception(
+ raise TypeError(
'First value for choice tuple must be a str; got: '
+ repr(choice))
if not isinstance(choice[1], value_type):
- raise Exception(
+ raise TypeError(
'Choice type does not match default value; choice:'
+ repr(choice) + '; setting:' + repr(setting))
if value_type not in (int, float):
- raise Exception(
+ raise TypeError(
'Choice type setting must have int or float default; '
'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 +279,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 +293,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 +302,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 +338,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 +348,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 +383,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:
@@ -435,7 +405,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,
@@ -457,14 +427,15 @@ 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._gametype, 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: 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)
@@ -509,5 +480,5 @@ class PlaylistEditGameWindow(ba.Window):
elif setting_type == int:
ba.textwidget(edit=ctrl, text=str(int(val)))
else:
- raise Exception('invalid vartype: ' + str(setting_type))
+ raise TypeError('invalid vartype: ' + str(setting_type))
self._settings[setting_name] = val
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..2381f6c5 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
@@ -36,14 +18,14 @@ class PlaylistMapSelectWindow(ba.Window):
"""Window to select a map."""
def __init__(self,
- gameclass: Type[ba.GameActivity],
+ gametype: Type[ba.GameActivity],
sessiontype: Type[ba.Session],
config: Dict[str, Any],
edit_info: Dict[str, Any],
completion_call: Callable[[Optional[Dict[str, Any]]], Any],
transition: str = 'in_right'):
from ba.internal import get_filtered_map_name
- self._gameclass = gameclass
+ self._gametype = gametype
self._sessiontype = sessiontype
self._config = config
self._completion_call = completion_call
@@ -55,16 +37,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.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
+ 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,
@@ -84,9 +69,9 @@ class PlaylistMapSelectWindow(ba.Window):
scale=1.1,
text=ba.Lstr(resource='mapSelectTitleText',
subs=[('${GAME}',
- self._gameclass.get_display_string())
+ self._gametype.get_display_string())
]),
- color=ba.app.title_color,
+ color=ba.app.ui.title_color,
h_align='center',
v_align='center')
v = height - 70
@@ -119,7 +104,7 @@ class PlaylistMapSelectWindow(ba.Window):
model_transparent = ba.getmodel('level_select_button_transparent')
self._maps = []
- map_list = self._gameclass.get_supported_maps(self._sessiontype)
+ map_list = self._gametype.get_supported_maps(self._sessiontype)
map_list_sorted = list(map_list)
map_list_sorted.sort()
unowned_maps = get_unowned_maps()
@@ -135,8 +120,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)
@@ -180,7 +164,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'))
@@ -225,30 +209,31 @@ class PlaylistMapSelectWindow(ba.Window):
def _on_store_press(self) -> None:
from bastd.ui import account
- from bastd.ui.store import browser
+ from bastd.ui.store.browser import StoreBrowserWindow
if _ba.get_account_state() != 'signed_in':
account.show_sign_in_prompt()
return
- browser.StoreBrowserWindow(modal=True,
- show_tab='maps',
- on_close_call=self._on_store_close,
- origin_widget=self._get_more_maps_button)
+ StoreBrowserWindow(modal=True,
+ show_tab=StoreBrowserWindow.TabID.MAPS,
+ on_close_call=self._on_store_close,
+ origin_widget=self._get_more_maps_button)
def _on_store_close(self) -> None:
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._gametype,
+ 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()
@@ -258,13 +243,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._gametype,
+ 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 a6aa7721..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
@@ -89,11 +71,13 @@ class SharePlaylistResultsWindow(ba.Window):
del origin # unused arg
self._width = 450
self._height = 300
+ uiscale = ba.app.ui.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'))
@@ -113,7 +97,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',
@@ -126,7 +110,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/playoptions.py b/assets/src/ba_data/python/bastd/ui/playoptions.py
index f312e3fd..af6725d9 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
@@ -44,11 +26,7 @@ class PlayOptionsWindow(popup.PopupWindow):
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
- from ba.internal import (getclass, have_pro,
- get_default_teams_playlist,
- get_default_free_for_all_playlist,
- filter_playlist)
- from ba.internal import get_map_class
+ from ba.internal import get_map_class, getclass, filter_playlist
from bastd.ui.playlist import PlaylistTypeVars
self._r = 'gameListWindow'
@@ -56,6 +34,10 @@ class PlayOptionsWindow(popup.PopupWindow):
self._pvars = PlaylistTypeVars(sessiontype)
self._transitioning_out = False
+ # We behave differently if we're being used for playlist selection
+ # vs starting a game directly (should make this more elegant).
+ self._selecting_mode = ba.app.ui.selecting_private_party_playlist
+
self._do_randomize_val = (ba.app.config.get(
self._pvars.config_name + ' Playlist Randomize', 0))
@@ -88,13 +70,7 @@ class PlayOptionsWindow(popup.PopupWindow):
max_columns = 5
name = playlist
if name == '__default__':
- if self._sessiontype is ba.FreeForAllSession:
- plst = get_default_free_for_all_playlist()
- elif self._sessiontype is ba.DualTeamSession:
- plst = get_default_teams_playlist()
- else:
- raise Exception('unrecognized session-type: ' +
- str(self._sessiontype))
+ plst = self._pvars.get_default_list_call()
else:
try:
plst = ba.app.config[self._pvars.config_name +
@@ -117,7 +93,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 +117,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
@@ -149,7 +125,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.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,
size=(self._width, self._height),
scale=scale)
@@ -204,7 +182,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}',
@@ -272,7 +250,7 @@ class PlayOptionsWindow(popup.PopupWindow):
autoselect=True,
textcolor=(0.8, 0.8, 0.8),
label=ba.Lstr(resource='teamNamesColorText'))
- if not have_pro():
+ if not ba.app.accounts.have_pro():
ba.imagewidget(
parent=self.root_widget,
size=(30, 30),
@@ -304,10 +282,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
@@ -343,23 +318,24 @@ class PlayOptionsWindow(popup.PopupWindow):
ba.widget(edit=self._show_tutorial_check_box,
up_widget=self._custom_colors_names_button)
- self._play_button = ba.buttonwidget(
+ self._ok_button = ba.buttonwidget(
parent=self.root_widget,
position=(70, 44),
size=(200, 45),
scale=1.8,
text_res_scale=1.5,
- on_activate_call=self._on_play_press,
+ on_activate_call=self._on_ok_press,
autoselect=True,
- label=ba.Lstr(resource='playText'))
+ label=ba.Lstr(
+ resource='okText' if self._selecting_mode else 'playText'))
- ba.widget(edit=self._play_button,
+ ba.widget(edit=self._ok_button,
up_widget=self._show_tutorial_check_box)
ba.containerwidget(edit=self.root_widget,
- start_button=self._play_button,
+ start_button=self._ok_button,
cancel_button=self._cancel_button,
- selected_child=self._play_button)
+ selected_child=self._ok_button)
# Update now and once per second.
self._update_timer = ba.Timer(1.0,
@@ -369,29 +345,25 @@ class PlayOptionsWindow(popup.PopupWindow):
self._update()
def _custom_colors_names_press(self) -> None:
- from ba.internal import have_pro
- from bastd.ui import account as accountui
- from bastd.ui import teamnamescolors
- from bastd.ui import purchase
- if not have_pro():
+ from bastd.ui.account import show_sign_in_prompt
+ from bastd.ui.teamnamescolors import TeamNamesColorsWindow
+ from bastd.ui.purchase import PurchaseWindow
+ if not ba.app.accounts.have_pro():
if _ba.get_account_state() != 'signed_in':
- accountui.show_sign_in_prompt()
+ show_sign_in_prompt()
else:
- purchase.PurchaseWindow(items=['pro'])
+ PurchaseWindow(items=['pro'])
self._transition_out()
return
assert self._custom_colors_names_button
- teamnamescolors.TeamNamesColorsWindow(
- scale_origin=self._custom_colors_names_button.
- get_screen_space_center())
+ TeamNamesColorsWindow(scale_origin=self._custom_colors_names_button.
+ get_screen_space_center())
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,
@@ -411,7 +383,7 @@ class PlayOptionsWindow(popup.PopupWindow):
def _on_cancel_press(self) -> None:
self._transition_out()
- def _on_play_press(self) -> None:
+ def _on_ok_press(self) -> None:
# Disallow if our playlist has disappeared.
if not self._does_target_playlist_exist():
@@ -426,12 +398,32 @@ class PlayOptionsWindow(popup.PopupWindow):
cfg = ba.app.config
cfg[self._pvars.config_name + ' Playlist Selection'] = self._playlist
+
+ # Head back to the gather window in playlist-select mode
+ # or start the game in regular mode.
+ if self._selecting_mode:
+ from bastd.ui.gather import GatherWindow
+ if self._sessiontype is ba.FreeForAllSession:
+ typename = 'ffa'
+ elif self._sessiontype is ba.DualTeamSession:
+ typename = 'teams'
+ else:
+ raise RuntimeError('Only teams and ffa currently supported')
+ cfg['Private Party Host Session Type'] = typename
+ ba.playsound(ba.getsound('gunCocking'))
+ ba.app.ui.set_main_menu_window(
+ GatherWindow(transition='in_right').get_root_widget())
+ self._transition_out(transition='out_left')
+ if self._delegate is not None:
+ self._delegate.on_play_options_window_run_game()
+ else:
+ _ba.fade_screen(False, endcall=self._run_selected_playlist)
+ _ba.lock_all_input()
+ self._transition_out(transition='out_left')
+ if self._delegate is not None:
+ self._delegate.on_play_options_window_run_game()
+
cfg.commit()
- _ba.fade_screen(False, endcall=self._run_selected_playlist)
- _ba.lock_all_input()
- self._transition_out(transition='out_left')
- if self._delegate is not None:
- self._delegate.on_play_options_window_run_game()
def _run_selected_playlist(self) -> None:
_ba.unlock_all_input()
diff --git a/assets/src/ba_data/python/bastd/ui/popup.py b/assets/src/ba_data/python/bastd/ui/popup.py
index 92000b96..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
@@ -153,7 +135,7 @@ class PopupMenuWindow(PopupWindow):
self._choices_disabled = list(choices_disabled)
self._done_building = False
if not choices:
- raise Exception('Must pass at least one choice')
+ raise TypeError('Must pass at least one choice')
self._width = width
self._scale = scale
if len(choices) > 8:
@@ -199,14 +181,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]
@@ -291,18 +277,20 @@ 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.ui.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)
if not choices:
- raise Exception('no choices given')
+ raise TypeError('no choices given')
self._choices_display = list(choices_display)
self._choices_disabled = list(choices_disabled)
self._width = width
@@ -313,7 +301,7 @@ class PopupMenu:
self._position = position
self._parent = parent
if not choices:
- raise Exception('Must pass at least one choice')
+ raise TypeError('Must pass at least one choice')
self._parent = parent
self._button_size = button_size
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/profile/browser.py b/assets/src/ba_data/python/bastd/ui/profile/browser.py
index 81f81b1c..e82fd29d 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
@@ -41,16 +23,16 @@ class ProfileBrowserWindow(ba.Window):
origin_widget: ba.Widget = None):
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
- from ba.internal import ensure_have_account_player_profile
self._in_main_menu = in_main_menu
if self._in_main_menu:
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.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
+ 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:
@@ -69,16 +51,17 @@ class ProfileBrowserWindow(ba.Window):
self._r = 'playerProfilesWindow'
# Ensure we've got an account-profile in cases where we're signed in.
- ensure_have_account_player_profile()
+ ba.app.accounts.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,
@@ -96,7 +79,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')
@@ -113,7 +96,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),
@@ -157,7 +141,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',
@@ -174,7 +158,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
@@ -184,20 +170,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()
+ if (not ba.app.accounts.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
@@ -212,9 +196,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
@@ -250,7 +235,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'),
@@ -258,9 +243,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.
@@ -268,13 +254,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:
@@ -282,6 +268,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)
@@ -290,13 +277,10 @@ 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())
+ items.sort(key=lambda x: asserttype(x[0], str).lower())
index = 0
account_name: Optional[str]
if _ba.get_account_state() == 'signed_in':
@@ -363,16 +347,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[type(self)] = 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.ui.window_states.get(type(self))
if sel_name == 'Scroll':
sel = self._scrollwidget
elif sel_name == 'New':
@@ -392,4 +373,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/profile/edit.py b/assets/src/ba_data/python/bastd/ui/profile/edit.py
index 128c6fdf..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
@@ -40,8 +22,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.get_name(), 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],
@@ -62,19 +45,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.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 = (
+ 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),
@@ -100,7 +85,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',
@@ -209,7 +194,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',
@@ -256,7 +241,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()
@@ -279,7 +264,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',
@@ -320,7 +305,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',
@@ -377,7 +362,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(
@@ -401,7 +386,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(
@@ -434,7 +419,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()
@@ -546,7 +531,7 @@ class EditProfileWindow(ba.Window):
elif picker_type == 'highlight':
initial_color = self._highlight
else:
- raise Exception('invalid picker_type: ' + picker_type)
+ raise ValueError('invalid picker_type: ' + picker_type)
colorpicker.ColorPicker(
parent=self._root_widget,
position=origin,
@@ -557,12 +542,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
@@ -605,7 +591,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 +616,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__'
@@ -642,8 +628,8 @@ 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()
+ from bastd.ui.profile.browser import ProfileBrowserWindow
+ new_name = self.getname().strip()
if not new_name:
ba.screenmessage(ba.Lstr(resource='nameNotEmptyText'))
@@ -679,8 +665,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 50ca401e..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
@@ -40,24 +22,25 @@ 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
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.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
- 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
+ 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),
@@ -83,7 +66,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',
@@ -94,7 +77,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',
@@ -124,7 +107,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),
@@ -138,11 +121,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/promocode.py b/assets/src/ba_data/python/bastd/ui/promocode.py
index af4aa198..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
@@ -53,12 +35,14 @@ class PromoCodeWindow(ba.Window):
self._modal = modal
self._r = 'promoCodeWindow'
+ uiscale = ba.app.ui.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,
@@ -108,24 +92,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/purchase.py b/assets/src/ba_data/python/bastd/ui/purchase.py
index fdf65b67..519fb489 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
@@ -44,16 +26,18 @@ class PurchaseWindow(ba.Window):
header_text = ba.Lstr(resource='unlockThisText',
fallback_resource='unlockThisInTheStoreText')
if len(items) != 1:
- raise Exception('expected exactly 1 item')
+ raise ValueError('expected exactly 1 item')
self._items = list(items)
self._width = 580
self._height = 520
+ uiscale = ba.app.ui.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,
@@ -130,12 +114,11 @@ class PurchaseWindow(ba.Window):
selected_child=self._purchase_button)
def _update(self) -> None:
- from ba.internal import have_pro
can_die = False
# We go away if we see that our target item is owned.
if self._items == ['pro']:
- if have_pro():
+ if ba.app.accounts.have_pro():
can_die = True
else:
if _ba.get_purchased(self._items[0]):
diff --git a/assets/src/ba_data/python/bastd/ui/qrcode.py b/assets/src/ba_data/python/bastd/ui/qrcode.py
index c695103a..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
@@ -31,7 +13,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.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
self._width = 450
self._height = 400
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 01652805..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
@@ -37,13 +19,14 @@ class ReportPlayerWindow(ba.Window):
scale_origin = origin_widget.get_screen_space_center()
overlay_stack = _ba.get_special_widget('overlay_stack')
+ uiscale = ba.app.ui.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),
@@ -87,7 +70,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 +83,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/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py b/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py
index eed95a9f..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
@@ -30,7 +12,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.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
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..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
@@ -44,10 +26,12 @@ class ServerDialogWindow(ba.Window):
txt_scale)
self._width = 500
self._height = 130 + min(200, txt_height)
+ uiscale = ba.app.ui.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/__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/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py
index 61c6dd1e..1d786905 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
@@ -39,7 +21,12 @@ 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
+ 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
@@ -53,20 +40,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.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
+ 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
@@ -75,16 +64,21 @@ class AdvancedSettingsWindow(ba.Window):
# In vr-mode, the internal keyboard is currently the *only* option,
# so no need to show this.
- self._show_always_use_internal_keyboard = (not app.vr_mode)
+ self._show_always_use_internal_keyboard = (not app.vr_mode
+ and not app.iircade_mode)
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
@@ -93,10 +87,11 @@ 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'
- if app.toolbars and app.small_ui:
+ 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
@@ -118,7 +113,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')
@@ -133,14 +128,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()
@@ -151,15 +146,28 @@ 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))
+
+ @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)
+ up_to_date = (ba.app.lang.language in self._complete_langs_list)
ba.textwidget(
edit=self._lang_status_text,
- text='' if ba.app.language == 'Test' else ba.Lstr(
+ text='' if ba.app.lang.language == 'Test' else ba.Lstr(
resource=self._r + '.translationNoUpdateNeededText')
if up_to_date else ba.Lstr(resource=self._r +
'.translationUpdateNeededText'),
@@ -179,7 +187,9 @@ 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
+
+ available_languages = ba.app.lang.available_languages
# Don't rebuild if the menu is open or if our language and
# language-list hasn't changed.
@@ -188,12 +198,11 @@ class AdvancedSettingsWindow(ba.Window):
# menu based on the language so still need this. ...however we could
# make this more limited to it only rebuilds that one menu instead
# of everything.
- if self._menu_open or (
- self._prev_lang == _ba.app.config.get('Lang', None)
- and self._prev_lang_list == ba.get_valid_languages()):
+ if self._menu_open or (self._prev_lang == _ba.app.config.get(
+ 'Lang', None) and self._prev_lang_list == available_languages):
return
self._prev_lang = _ba.app.config.get('Lang', None)
- self._prev_lang_list = ba.get_valid_languages()
+ self._prev_lang_list = available_languages
# Clear out our sub-container.
children = self._subcontainer.get_children()
@@ -236,11 +245,11 @@ 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')
- languages = ba.get_valid_languages()
+ languages = _ba.app.lang.available_languages
cur_lang = _ba.app.config.get('Lang', None)
if cur_lang is None:
cur_lang = 'Auto'
@@ -253,7 +262,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 = {}
@@ -281,9 +290,9 @@ class AdvancedSettingsWindow(ba.Window):
button_size=(250, 60),
choices_display=([
ba.Lstr(value=(ba.Lstr(resource='autoText').evaluate() + ' (' +
- ba.Lstr(translate=(
- 'languages',
- ba.app.default_language)).evaluate() + ')'))
+ ba.Lstr(translate=('languages',
+ ba.app.lang.default_language
+ )).evaluate() + ')'))
] + [ba.Lstr(value=langs_full[l]) for l in languages]),
current_choice=cur_lang)
@@ -357,6 +366,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
@@ -412,7 +444,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),
@@ -423,32 +455,16 @@ class AdvancedSettingsWindow(ba.Window):
ba.open_url,
'http://www.froemling.net/docs/bombsquad-modding-guide'))
- v -= self._spacing * 1.8
+ v -= self._spacing * 2.0
- self._enable_package_mods_checkbox = ConfigCheckBox(
+ self._plugins_button = ba.buttonwidget(
parent=self._subcontainer,
- position=(80, v),
- size=(self._sub_width - 100, 30),
- configkey='Enable Package Mods',
+ position=(self._sub_width / 2 - this_button_width / 2, v - 10),
+ size=(this_button_width, 60),
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')
+ label=ba.Lstr(resource='pluginsText'),
+ text_scale=1.0,
+ on_activate_call=self._on_plugins_button_press)
v -= self._spacing * 0.6
@@ -490,15 +506,10 @@ 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)
- 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:
@@ -521,18 +532,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
@@ -542,25 +553,34 @@ 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 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
@@ -578,10 +598,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'
@@ -589,32 +614,27 @@ 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._enable_package_mods_checkbox.widget:
- sel_name = 'PackageMods'
elif sel == self._language_inform_checkbox:
sel_name = 'LangInform'
else:
- raise Exception('unrecognized selection')
+ raise ValueError(f'unrecognized selection \'{sel}\'')
elif sel == self._back_button:
sel_name = 'Back'
else:
- raise Exception('unrecognized selection')
- ba.app.window_states[self.__class__.__name__] = {
- 'sel_name': sel_name
- }
+ raise ValueError(f'unrecognized selection \'{sel}\'')
+ ba.app.ui.window_states[type(self)] = {'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.ui.window_states.get(type(self),
+ {}).get('sel_name')
if sel_name == 'Back':
sel = self._back_button
else:
@@ -630,10 +650,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()
@@ -641,20 +666,20 @@ 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 == 'PackageMods':
- sel = self._enable_package_mods_checkbox.widget
elif sel_name == 'LangInform':
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('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
@@ -663,7 +688,7 @@ class AdvancedSettingsWindow(ba.Window):
self._menu_open = False
def _on_menu_choice(self, choice: str) -> None:
- ba.setlanguage(None if choice == 'Auto' else choice)
+ ba.app.lang.setlanguage(None if choice == 'Auto' else choice)
self._save_state()
ba.timer(0.1, ba.WeakCall(self._rebuild), timetype=ba.TimeType.REAL)
@@ -679,9 +704,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 df29572e..ede3823d 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
@@ -39,6 +21,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:
@@ -48,23 +36,24 @@ 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.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
- # 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.ui.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.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)
@@ -85,7 +74,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)
@@ -99,10 +88,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
@@ -128,7 +117,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,
@@ -148,7 +137,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'))
@@ -196,47 +185,61 @@ 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:
+ """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
+ 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(
- 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 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(
- 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 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(
- 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 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(
- 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 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(
- 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:
@@ -252,20 +255,15 @@ class AllSettingsWindow(ba.Window):
elif sel == self._back_button:
sel_name = 'Back'
else:
- raise Exception('unrecognized selection')
- ba.app.window_states[self.__class__.__name__] = {
- 'sel_name': sel_name
- }
+ raise ValueError(f'unrecognized selection \'{sel}\'')
+ ba.app.ui.window_states[type(self)] = {'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.ui.window_states.get(type(self),
+ {}).get('sel_name')
sel: Optional[ba.Widget]
if sel_name == 'Controllers':
sel = self._controllers_button
@@ -282,4 +280,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 b5f2c424..99f98d93 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
@@ -74,8 +56,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.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
super().__init__(root_widget=ba.containerwidget(
@@ -83,7 +66,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,
@@ -102,7 +85,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')
@@ -121,7 +104,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
@@ -206,11 +189,11 @@ 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:
- ba.print_exception('error wiring AudioSettingsWindow')
+ ba.print_exception('Error wiring AudioSettingsWindow.')
self._restore_state()
@@ -236,8 +219,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
@@ -245,8 +229,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:
@@ -266,17 +251,14 @@ class AudioSettingsWindow(ba.Window):
elif sel == self._vr_head_relative_audio_button:
sel_name = 'VRHeadRelative'
else:
- raise Exception('unrecognized selected widget')
- ba.app.window_states[self.__class__.__name__] = sel_name
+ raise ValueError(f'unrecognized selection \'{sel}\'')
+ ba.app.ui.window_states[type(self)] = 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.ui.window_states.get(type(self))
sel: Optional[ba.Widget]
if sel_name == 'SoundMinus':
sel = self._sound_volume_numedit.minusbutton
@@ -297,4 +279,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 00e81723..ee06d279 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
@@ -59,17 +41,17 @@ 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
width = 460.0
- height = 135.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
@@ -91,9 +73,9 @@ 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
+ height += spacing
show_keyboard_p2 = False if app.vr_mode else show_keyboard
if show_keyboard_p2:
height += spacing
@@ -110,46 +92,48 @@ 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':
- 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':
+ 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
+ uiscale = ba.app.ui.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))
+ 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(
parent=self._root_widget,
position=(35, height - 60),
@@ -162,7 +146,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
@@ -176,7 +160,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,
@@ -195,7 +179,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:
@@ -214,7 +198,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:
@@ -238,7 +222,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:
@@ -267,7 +251,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:
@@ -285,7 +269,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
@@ -297,7 +281,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
@@ -309,7 +293,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
@@ -340,7 +324,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:
@@ -367,7 +351,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,
@@ -377,9 +361,9 @@ 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
+ v -= spacing * 1.5
self._restore_state()
def _set_mac_controller_subsystem(self, val: str) -> None:
@@ -389,67 +373,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.get_input_device('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.get_input_device('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()
@@ -471,13 +457,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[type(self)] = 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.ui.window_states.get(type(self))
if sel_name == 'GamePads':
sel = self._gamepads_button
elif sel_name == 'Touch':
@@ -503,9 +486,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 046f9b12..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
@@ -39,16 +21,15 @@ 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;
- # 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
@@ -61,11 +42,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.ui.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.
@@ -188,7 +170,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,
@@ -202,7 +184,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 +194,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 +217,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')
@@ -352,7 +334,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)"""
@@ -710,15 +692,15 @@ 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 (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)
@@ -743,7 +725,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,
@@ -758,9 +740,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):
@@ -776,17 +758,19 @@ 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
width = 400
height = 150
+ uiscale = ba.app.ui.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)),
@@ -836,7 +820,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/gamepadadvanced.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py
index cc8de99c..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
@@ -41,34 +23,35 @@ 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.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
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,
- color=ba.app.title_color,
+ color=ba.app.ui.title_color,
h_align='center',
v_align='center')
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'),
@@ -88,19 +71,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)
@@ -403,10 +384,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/settings/gamepadselect.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py
index daccdabf..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
@@ -41,7 +23,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,16 +31,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
- 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,
+ 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),
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',
@@ -77,8 +62,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),
@@ -97,10 +83,13 @@ class GamepadSelectWindow(ba.Window):
spacing = 40
self._r = 'configGamepadSelectWindow'
+ uiscale = ba.app.ui.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),
@@ -119,7 +108,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')
@@ -136,7 +125,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
@@ -157,5 +146,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 6fe5477e..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
@@ -57,14 +39,14 @@ class GraphicsSettingsWindow(ba.Window):
spacing = 32
self._have_selected_child = False
- interface_type = app.interface_type
+ uiscale = app.ui.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 +65,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.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
v = height - 50
v -= spacing * 1.15
@@ -93,7 +76,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),
@@ -111,7 +94,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')
@@ -152,7 +135,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:
@@ -171,7 +154,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',
@@ -199,7 +182,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',
@@ -218,7 +201,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
@@ -231,7 +214,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',
@@ -305,7 +288,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',
@@ -366,8 +349,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 7ca300f1..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
@@ -45,17 +27,18 @@ 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.ui.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, 5) if uiscale is ba.UIScale.SMALL 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 +46,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',
@@ -74,7 +57,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,
@@ -82,9 +65,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)
@@ -95,13 +78,13 @@ 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),
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,
@@ -119,10 +102,10 @@ 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 -= 45
+ v -= 40
v -= 10
v -= self._spacing * 2.2
v += 25
@@ -197,8 +180,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,
@@ -223,16 +208,21 @@ 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
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'))
+
+ # 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()
@@ -245,7 +235,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,
@@ -254,14 +244,14 @@ 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):
"""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
@@ -269,10 +259,12 @@ class AwaitKeyboardInputWindow(ba.Window):
width = 400
height = 150
+ uiscale = ba.app.ui.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),
@@ -288,17 +280,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/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
new file mode 100644
index 00000000..72e44805
--- /dev/null
+++ b/assets/src/ba_data/python/bastd/ui/settings/plugins.py
@@ -0,0 +1,156 @@
+# Released under the MIT License. See LICENSE for details.
+#
+"""Plugin settings UI."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import ba
+
+if TYPE_CHECKING:
+ from typing import Tuple, Optional, Dict
+
+
+class PluginSettingsWindow(ba.Window):
+ """Window for configuring plugins."""
+
+ def __init__(self,
+ transition: str = 'in_right',
+ origin_widget: ba.Widget = None):
+ # pylint: disable=too-many-locals
+ 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.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
+ 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),
+ 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)
+
+ if ba.app.meta.metascan is None:
+ ba.screenmessage('Still scanning plugins; please try again.',
+ color=(1, 0, 0))
+ ba.playsound(ba.getsound('error'))
+ pluglist = ba.app.plugins.potential_plugins
+ plugstates: Dict[str, Dict] = ba.app.config.setdefault('Plugins', {})
+ assert isinstance(plugstates, dict)
+ for i, availplug in enumerate(pluglist):
+ active = availplug.class_path in ba.app.plugins.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.
+ 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)
+
+ self._restore_state()
+
+ 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))
+ 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
+
+ def _restore_state(self) -> None:
+ pass
+
+ 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())
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..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
@@ -34,10 +16,12 @@ class PS3ControllerSettingsWindow(ba.Window):
height = 330 if _ba.is_running_on_fire_tv() else 540
spacing = 40
self._r = 'ps3ControllersWindow'
+ uiscale = ba.app.ui.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),
@@ -56,7 +40,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')
@@ -118,5 +102,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 0db78e6e..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
@@ -34,11 +16,13 @@ class RemoteAppSettingsWindow(ba.Window):
width = 700
height = 390
spacing = 40
+ uiscale = ba.app.ui.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),
@@ -55,7 +39,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')
@@ -129,5 +113,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 1c090f07..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
@@ -39,14 +21,16 @@ class TestingWindow(ba.Window):
title: ba.Lstr,
entries: List[Dict[str, Any]],
transition: str = 'in_right'):
+ uiscale = ba.app.ui.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,
@@ -60,7 +44,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,
@@ -75,7 +59,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,
@@ -106,7 +90,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] = (
@@ -131,15 +115,14 @@ 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),
- 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),
@@ -153,7 +136,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),
@@ -161,37 +144,36 @@ 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:
if entry['name'] == name:
return entry
- raise Exception(f'Entry not found: {name}')
+ raise ba.NotFoundError(f'Entry not found: {name}')
def _on_reset_press(self) -> None:
for entry in self._entries:
_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
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 7dbc3d80..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
@@ -45,10 +27,12 @@ class TouchscreenSettingsWindow(ba.Window):
_ba.set_touchscreen_editing(True)
+ uiscale = ba.app.ui.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),
@@ -63,7 +47,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')
@@ -82,26 +66,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()
@@ -143,20 +125,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,
@@ -181,28 +162,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,
@@ -249,6 +230,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/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 dfca0b33..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
@@ -52,7 +34,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 +90,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 +114,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 +187,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 ac771431..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
@@ -39,10 +21,12 @@ class XBox360ControllerSettingsWindow(ba.Window):
width = 700
height = 300 if _ba.is_running_on_fire_tv() else 485
spacing = 40
+ uiscale = ba.app.ui.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),
@@ -61,7 +45,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')
@@ -126,5 +110,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/__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/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py
index 044fd865..7989d329 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
@@ -38,6 +20,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 +34,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.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
+ 370 if uiscale is ba.UIScale.MEDIUM else 440)
spacing = 40.0
v = self._height - 40.0
v -= spacing * 1.0
@@ -64,10 +48,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.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
self._back_button = None
else:
self._back_button = ba.buttonwidget(
@@ -87,7 +72,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')
@@ -98,7 +83,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,
@@ -206,8 +192,8 @@ 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)
- self._col = ba.columnwidget(parent=scrollwidget)
+ if ba.app.ui.use_toolbars else self._scrollwidget)
+ self._col = ba.columnwidget(parent=scrollwidget, border=2, margin=0)
self._soundtracks: Optional[Dict[str, Any]] = None
self._selected_soundtrack: Optional[str] = None
@@ -225,8 +211,7 @@ class SoundtrackBrowserWindow(ba.Window):
on_cancel_call=self._back)
def _update(self) -> None:
- from ba.internal import have_pro_options
- have = have_pro_options()
+ have = ba.app.accounts.have_pro_options()
for lock in self._lock_images:
ba.imagewidget(edit=lock, opacity=0.0 if have else 1.0)
@@ -245,11 +230,10 @@ class SoundtrackBrowserWindow(ba.Window):
def _delete_soundtrack(self) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui import purchase
- from bastd.ui import confirm
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.purchase import PurchaseWindow
+ from bastd.ui.confirm import ConfirmWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
if self._selected_soundtrack is None:
return
@@ -259,17 +243,16 @@ class SoundtrackBrowserWindow(ba.Window):
'.cantDeleteDefaultText'),
color=(1, 0, 0))
else:
- confirm.ConfirmWindow(
+ ConfirmWindow(
ba.Lstr(resource=self._r + '.deleteConfirmText',
subs=[('${NAME}', self._selected_soundtrack)]),
self._do_delete_soundtrack, 450, 150)
def _duplicate_soundtrack(self) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui import purchase
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.purchase import PurchaseWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
cfg = ba.app.config
cfg.setdefault('Soundtracks', {})
@@ -333,26 +316,24 @@ 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
- from ba.internal import have_pro_options
- from bastd.ui import purchase
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.purchase import PurchaseWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
ba.playsound(ba.getsound('swish'))
self._edit_soundtrack()
def _edit_soundtrack(self) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui import purchase
- from bastd.ui.soundtrack import edit as stedit
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.purchase import PurchaseWindow
+ from bastd.ui.soundtrack.edit import SoundtrackEditWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
if self._selected_soundtrack is None:
return
@@ -365,8 +346,9 @@ 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(
+ SoundtrackEditWindow(existing_soundtrack=self._selected_soundtrack
+ ).get_root_widget())
def _get_soundtrack_display_name(self, soundtrack: str) -> ba.Lstr:
if soundtrack == '__default__':
@@ -374,27 +356,23 @@ 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
# 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())
+ 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:
@@ -454,15 +432,14 @@ class SoundtrackBrowserWindow(ba.Window):
def _new_soundtrack(self) -> None:
# pylint: disable=cyclic-import
- from ba.internal import have_pro_options
- from bastd.ui import purchase
- from bastd.ui.soundtrack import edit as stedit
- if not have_pro_options():
- purchase.PurchaseWindow(items=['pro'])
+ from bastd.ui.purchase import PurchaseWindow
+ from bastd.ui.soundtrack.edit import SoundtrackEditWindow
+ if not ba.app.accounts.have_pro_options():
+ PurchaseWindow(items=['pro'])
return
self._save_state()
ba.containerwidget(edit=self._root_widget, transition='out_left')
- stedit.SoundtrackEditWindow(existing_soundtrack=None)
+ SoundtrackEditWindow(existing_soundtrack=None)
def _create_done(self, new_soundtrack: str) -> None:
if new_soundtrack is not None:
@@ -485,17 +462,14 @@ class SoundtrackBrowserWindow(ba.Window):
elif sel == self._back_button:
sel_name = 'Back'
else:
- raise Exception('unrecognized selection')
- ba.app.window_states[self.__class__.__name__] = sel_name
+ raise ValueError(f'unrecognized selection \'{sel}\'')
+ ba.app.ui.window_states[type(self)] = 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.ui.window_states.get(type(self))
if sel_name == 'Scroll':
sel = self._scrollwidget
elif sel_name == 'New':
@@ -510,4 +484,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 cf0507ab..e264d115 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
@@ -39,20 +21,22 @@ 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')
- 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.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
+ 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),
@@ -76,13 +60,13 @@ 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)
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 +74,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 +113,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
@@ -153,18 +137,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()
@@ -176,7 +157,6 @@ class SoundtrackEditWindow(ba.Window):
ba.widget(edit=cancel_button, down_widget=self._text_field)
def _refresh(self) -> None:
- from ba.deprecated import get_resource
for widget in self._col.get_children():
widget.delete()
@@ -202,21 +182,19 @@ class SoundtrackEditWindow(ba.Window):
'Scores',
'Victory',
]
+
# FIXME: We should probably convert this to use translations.
- type_names_translated = get_resource('soundtrackTypeNames')
+ type_names_translated = ba.app.lang.get_resource('soundtrackTypeNames')
prev_type_button: Optional[ba.Widget] = None
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)
- try:
- type_name = type_names_translated[song_type]
- except Exception:
- type_name = song_type
+ selection_loops_to_parent=True)
+ type_name = type_names_translated.get(song_type, song_type)
ba.textwidget(parent=row,
size=(230, 25),
always_highlight=True,
@@ -232,7 +210,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)
@@ -311,8 +289,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:
@@ -326,7 +304,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())
@@ -373,8 +351,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
@@ -415,8 +394,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 22304ea8..142a6bc4 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
@@ -64,10 +46,19 @@ class SoundtrackEntryTypeSelectWindow(ba.Window):
if do_music_folder:
self._height += spacing
+ uiscale = ba.app.ui.uiscale
+
+ # NOTE: When something is selected, we close our UI and kick off
+ # another window which then calls us back when its done, so the
+ # standard UI-cleanup-check complains that something is holding on
+ # to our instance after its ui is gone. Should restructure in a
+ # cleaner way, but just disabling that check for now.
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)),
+ cleanupcheck=False)
btn = ba.buttonwidget(parent=self._root_widget,
position=(35, self._height - 65),
size=(160, 60),
@@ -80,7 +71,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')
@@ -89,7 +80,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',
@@ -149,7 +140,8 @@ class SoundtrackEntryTypeSelectWindow(ba.Window):
def _on_mac_music_app_playlist_press(self) -> None:
music = ba.app.music
- from bastd.ui.soundtrack import macmusicapp
+ from bastd.ui.soundtrack.macmusicapp import (
+ MacMusicAppPlaylistSelectWindow)
ba.containerwidget(edit=self._root_widget, transition='out_left')
current_playlist_entry: Optional[str]
@@ -159,33 +151,35 @@ 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(
+ 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
+ from bastd.ui.fileselector import FileSelectorWindow
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(
+ 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
+ from bastd.ui.fileselector import FileSelectorWindow
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(
+ 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..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
@@ -52,31 +34,26 @@ 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),
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)
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 +70,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 +80,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/specialoffer.py b/assets/src/ba_data/python/bastd/ui/specialoffer.py
index f32432f0..3e3a5421 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
@@ -56,11 +38,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
@@ -87,11 +73,13 @@ class SpecialOfferWindow(ba.Window):
self._offer = copy.deepcopy(offer)
self._width = 580
self._height = 590
+ uiscale = ba.app.ui.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']:
@@ -109,16 +97,26 @@ 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 = ''
@@ -210,8 +208,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}',
@@ -245,7 +243,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),
@@ -333,7 +331,6 @@ class SpecialOfferWindow(ba.Window):
text=str(self._cancel_delay) if self._cancel_delay > 0 else '')
def _update(self) -> None:
- from ba.internal import have_pro
# If we've got seconds left on our countdown, update it.
if self._cancel_delay > 0:
@@ -344,7 +341,7 @@ class SpecialOfferWindow(ba.Window):
# We go away if we see that our target item is owned.
if self._offer_item == 'pro':
- if have_pro():
+ if _ba.app.accounts.have_pro():
can_die = True
else:
if _ba.get_purchased(self._offer_item):
@@ -437,8 +434,9 @@ def show_offer() -> bool:
# Space things out a bit so we don't hit the poor user with an ad and
# then an in-game offer.
has_been_long_enough_since_ad = True
- if (app.last_ad_completion_time is not None and
- (ba.time(ba.TimeType.REAL) - app.last_ad_completion_time < 30.0)):
+ if (app.ads.last_ad_completion_time is not None and
+ (ba.time(ba.TimeType.REAL) - app.ads.last_ad_completion_time <
+ 30.0)):
has_been_long_enough_since_ad = False
if app.special_offer is not None and has_been_long_enough_since_ad:
@@ -462,6 +460,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/__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/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py
index 953aab33..990f4067 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
@@ -25,6 +7,7 @@ from __future__ import annotations
import copy
import math
import weakref
+from enum import Enum
from typing import TYPE_CHECKING
import _ba
@@ -38,27 +21,28 @@ if TYPE_CHECKING:
class StoreBrowserWindow(ba.Window):
"""Window for browsing the store."""
- def _update_get_tickets_button_pos(self) -> None:
- if self._get_tickets_button:
- pos = (self._width - 252 -
- (self._x_inset + (47 if ba.app.small_ui
- and _ba.is_party_icon_visible() else 0)),
- self._height - 70)
- ba.buttonwidget(edit=self._get_tickets_button, position=pos)
+ class TabID(Enum):
+ """Our available tab types."""
+ EXTRAS = 'extras'
+ MAPS = 'maps'
+ MINIGAMES = 'minigames'
+ CHARACTERS = 'characters'
+ ICONS = 'icons'
def __init__(self,
transition: str = 'in_right',
modal: bool = False,
- show_tab: str = None,
+ show_tab: StoreBrowserWindow.TabID = None,
on_close_call: Callable[[], Any] = None,
back_location: str = None,
origin_widget: ba.Widget = None):
# pylint: disable=too-many-statements
# pylint: disable=too-many-locals
- from bastd.ui import tabs
+ from bastd.ui.tabs import TabRow
from ba import SpecialChar
app = ba.app
+ uiscale = app.ui.uiscale
ba.set_analytics_screen('Store Window')
@@ -81,11 +65,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._current_tab: Optional[str] = None
- extra_top = 30 if app.small_ui else 0
+ 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[StoreBrowserWindow.TabID] = None
+ extra_top = 30 if uiscale is ba.UIScale.SMALL else 0
self._request: Any = None
self._r = 'store'
@@ -95,12 +80,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,
@@ -113,17 +97,27 @@ class StoreBrowserWindow(ba.Window):
on_activate_call=self._back)
ba.containerwidget(edit=self._root_widget, cancel_button=btn)
- self._get_tickets_button = ba.buttonwidget(
- parent=self._root_widget,
- size=(210, 65),
- on_activate_call=self._on_get_more_tickets_press,
- autoselect=True,
- scale=0.9,
- text_scale=1.4,
- left_widget=self._back_button,
- color=(0.7, 0.5, 0.85),
- textcolor=(0.2, 1.0, 0.2),
- label=ba.Lstr(resource='getTicketsWindow.titleText'))
+ self._ticket_count_text: Optional[ba.Widget] = None
+ self._get_tickets_button: Optional[ba.Widget] = None
+
+ if ba.app.allow_ticket_purchases:
+ self._get_tickets_button = ba.buttonwidget(
+ parent=self._root_widget,
+ size=(210, 65),
+ on_activate_call=self._on_get_more_tickets_press,
+ autoselect=True,
+ scale=0.9,
+ text_scale=1.4,
+ left_widget=self._back_button,
+ color=(0.7, 0.5, 0.85),
+ textcolor=(0.2, 1.0, 0.2),
+ label=ba.Lstr(resource='getTicketsWindow.titleText'))
+ else:
+ self._ticket_count_text = ba.textwidget(parent=self._root_widget,
+ size=(210, 64),
+ color=(0.2, 1.0, 0.2),
+ h_align='center',
+ v_align='center')
# Move this dynamically to keep it out of the way of the party icon.
self._update_get_tickets_button_pos()
@@ -132,8 +126,9 @@ class StoreBrowserWindow(ba.Window):
ba.WeakCall(self._update_get_tickets_button_pos),
repeat=True,
timetype=ba.TimeType.REAL)
- ba.widget(edit=self._back_button,
- right_widget=self._get_tickets_button)
+ if self._get_tickets_button:
+ ba.widget(edit=self._back_button,
+ right_widget=self._get_tickets_button)
self._ticket_text_update_timer = ba.Timer(
1.0,
ba.WeakCall(self._update_tickets_text),
@@ -158,7 +153,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',
@@ -175,29 +170,29 @@ class StoreBrowserWindow(ba.Window):
tab_buffer_h = 250 + 2 * x_inset
tabs_def = [
- ('extras', ba.Lstr(resource=self._r + '.extrasText')),
- ('maps', ba.Lstr(resource=self._r + '.mapsText')),
- ('minigames', ba.Lstr(resource=self._r + '.miniGamesText')),
- ('characters', ba.Lstr(resource=self._r + '.charactersText')),
- ('icons', ba.Lstr(resource=self._r + '.iconsText')),
+ (self.TabID.EXTRAS, ba.Lstr(resource=self._r + '.extrasText')),
+ (self.TabID.MAPS, ba.Lstr(resource=self._r + '.mapsText')),
+ (self.TabID.MINIGAMES,
+ ba.Lstr(resource=self._r + '.miniGamesText')),
+ (self.TabID.CHARACTERS,
+ ba.Lstr(resource=self._r + '.charactersText')),
+ (self.TabID.ICONS, ba.Lstr(resource=self._r + '.iconsText')),
]
- tab_results = tabs.create_tab_buttons(self._root_widget,
- tabs_def,
- pos=(tab_buffer_h * 0.5,
- self._height - 130),
- size=(self._width - tab_buffer_h,
- 50),
- on_select_call=self._set_tab,
- return_extra_info=True)
+ self._tab_row = TabRow(self._root_widget,
+ tabs_def,
+ pos=(tab_buffer_h * 0.5, self._height - 130),
+ size=(self._width - tab_buffer_h, 50),
+ on_select_call=self._set_tab)
- self._purchasable_count_widgets: Dict[str, Dict[str, Any]] = {}
+ self._purchasable_count_widgets: Dict[StoreBrowserWindow.TabID,
+ Dict[str, Any]] = {}
# Create our purchasable-items tags and have them update over time.
- for i, tab in enumerate(tabs_def):
- pos = tab_results['positions'][i]
- size = tab_results['sizes'][i]
- button = tab_results['buttons_indexed'][i]
+ for tab_id, tab in self._tab_row.tabs.items():
+ pos = tab.position
+ size = tab.size
+ button = tab.button
rad = 10
center = (pos[0] + 0.1 * size[0], pos[1] + 0.9 * size[1])
img = ba.imagewidget(parent=self._root_widget,
@@ -247,7 +242,7 @@ class StoreBrowserWindow(ba.Window):
shadow=0.0,
flatness=1.0,
color=(0, 1, 0))
- self._purchasable_count_widgets[tab[0]] = {
+ self._purchasable_count_widgets[tab_id] = {
'img': img,
'text': txt,
'sale_img': sale_img,
@@ -260,10 +255,8 @@ class StoreBrowserWindow(ba.Window):
repeat=True)
self._update_tabs()
- self._tab_buttons = tab_results['buttons']
-
- if self._get_tickets_button is not None:
- last_tab_button = self._tab_buttons[tabs_def[-1][0]]
+ if self._get_tickets_button:
+ last_tab_button = self._tab_row.tabs[tabs_def[-1][0]].button
ba.widget(edit=self._get_tickets_button,
down_widget=last_tab_button)
ba.widget(edit=last_tab_button,
@@ -277,6 +270,17 @@ class StoreBrowserWindow(ba.Window):
self._status_textwidget: Optional[ba.Widget] = None
self._restore_state()
+ def _update_get_tickets_button_pos(self) -> None:
+ uiscale = ba.app.ui.uiscale
+ pos = (self._width - 252 - (self._x_inset +
+ (47 if uiscale is ba.UIScale.SMALL
+ and _ba.is_party_icon_visible() else 0)),
+ self._height - 70)
+ if self._get_tickets_button:
+ ba.buttonwidget(edit=self._get_tickets_button, position=pos)
+ if self._ticket_count_text:
+ ba.textwidget(edit=self._ticket_count_text, position=pos)
+
def _restore_purchases(self) -> None:
from bastd.ui import account
if _ba.get_account_state() != 'signed_in':
@@ -289,9 +293,8 @@ class StoreBrowserWindow(ba.Window):
get_available_purchase_count)
if not self._root_widget:
return
- for tab_name, tab_data in list(
- self._purchasable_count_widgets.items()):
- sale_time = get_available_sale_time(tab_name)
+ for tab_id, tab_data in list(self._purchasable_count_widgets.items()):
+ sale_time = get_available_sale_time(tab_id.value)
if sale_time is not None:
ba.textwidget(edit=tab_data['sale_title_text'],
@@ -307,7 +310,7 @@ class StoreBrowserWindow(ba.Window):
ba.textwidget(edit=tab_data['sale_title_text'], text='')
ba.textwidget(edit=tab_data['sale_time_text'], text='')
ba.imagewidget(edit=tab_data['sale_img'], opacity=0.0)
- count = get_available_purchase_count(tab_name)
+ count = get_available_purchase_count(tab_id.value)
if count > 0:
ba.textwidget(edit=tab_data['text'], text=str(count))
@@ -326,21 +329,23 @@ class StoreBrowserWindow(ba.Window):
_ba.get_account_ticket_count())
else:
sval = ba.Lstr(resource='getTicketsWindow.titleText')
- ba.buttonwidget(edit=self._get_tickets_button, label=sval)
+ if self._get_tickets_button:
+ ba.buttonwidget(edit=self._get_tickets_button, label=sval)
+ if self._ticket_count_text:
+ ba.textwidget(edit=self._ticket_count_text, text=sval)
- def _set_tab(self, tab: str) -> None:
- from bastd.ui import tabs
- if self._current_tab == tab:
+ def _set_tab(self, tab_id: TabID) -> None:
+ if self._current_tab is tab_id:
return
- self._current_tab = tab
+ self._current_tab = tab_id
# We wanna preserve our current tab between runs.
cfg = ba.app.config
- cfg['Store Tab'] = tab
+ cfg['Store Tab'] = tab_id.value
cfg.commit()
# Update tab colors based on which is selected.
- tabs.update_tab_button_colors(self._tab_buttons, tab)
+ self._tab_row.update_appearance(tab_id)
# (Re)create scroll widget.
if self._scrollwidget:
@@ -351,19 +356,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()
@@ -381,7 +383,7 @@ class StoreBrowserWindow(ba.Window):
def __init__(self, window: StoreBrowserWindow):
self._window = weakref.ref(window)
- data = {'tab': tab}
+ data = {'tab': tab_id.value}
ba.timer(0.1,
ba.WeakCall(self._on_response, data),
timetype=ba.TimeType.REAL)
@@ -449,13 +451,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,
@@ -534,7 +536,7 @@ class StoreBrowserWindow(ba.Window):
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
- from ba.internal import have_pro, get_available_sale_time
+ from ba.internal import get_available_sale_time
from ba import SpecialChar
if not self._root_widget:
return
@@ -558,7 +560,7 @@ class StoreBrowserWindow(ba.Window):
for b_type, b_info in self.button_infos.items():
if b_type in ['upgrades.pro', 'pro']:
- purchased = have_pro()
+ purchased = _ba.app.accounts.have_pro()
else:
purchased = _ba.get_purchased(b_type)
@@ -718,6 +720,8 @@ class StoreBrowserWindow(ba.Window):
self._sections = copy.deepcopy(store_data[sdata['tab']])
self._height: Optional[float] = None
+ uiscale = ba.app.ui.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:
@@ -776,11 +781,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':
@@ -959,23 +963,23 @@ class StoreBrowserWindow(ba.Window):
# Also update them immediately.
self._store_window.update_buttons()
- if self._current_tab in ('extras', 'minigames', 'characters',
- 'maps', 'icons'):
+ if self._current_tab in (self.TabID.EXTRAS, self.TabID.MINIGAMES,
+ self.TabID.CHARACTERS, self.TabID.MAPS,
+ self.TabID.ICONS):
store = _Store(self, data, self._scroll_width)
assert self._scrollwidget is not None
store.instantiate(
scrollwidget=self._scrollwidget,
- tab_button=self._tab_buttons[self._current_tab])
+ tab_button=self._tab_row.tabs[self._current_tab].button)
else:
cnt = ba.containerwidget(parent=self._scrollwidget,
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,
@@ -992,88 +996,97 @@ class StoreBrowserWindow(ba.Window):
def _save_state(self) -> None:
try:
sel = self._root_widget.get_selected_child()
+ selected_tab_ids = [
+ tab_id for tab_id, tab in self._tab_row.tabs.items()
+ if sel == tab.button
+ ]
if sel == self._get_tickets_button:
sel_name = 'GetTickets'
elif sel == self._scrollwidget:
sel_name = 'Scroll'
elif sel == self._back_button:
sel_name = 'Back'
- elif sel in list(self._tab_buttons.values()):
- sel_name = 'Tab:' + list(self._tab_buttons.keys())[list(
- self._tab_buttons.values()).index(sel)]
+ elif selected_tab_ids:
+ assert len(selected_tab_ids) == 1
+ sel_name = f'Tab:{selected_tab_ids[0].value}'
else:
- raise Exception('unrecognized selection')
- ba.app.window_states[self.__class__.__name__] = {
+ raise ValueError(f'unrecognized selection \'{sel}\'')
+ ba.app.ui.window_states[type(self)] = {
'sel_name': sel_name,
- '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:
+ from efro.util import enum_by_value
try:
sel: Optional[ba.Widget]
+ sel_name = ba.app.ui.window_states.get(type(self),
+ {}).get('sel_name')
+ assert isinstance(sel_name, (str, type(None)))
+
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
+ current_tab = enum_by_value(self.TabID,
+ ba.app.config.get('Store Tab'))
+ except ValueError:
+ current_tab = self.TabID.CHARACTERS
+
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:
- current_tab = 'characters'
- if sel_name == 'GetTickets':
+ if sel_name == 'GetTickets' and self._get_tickets_button:
sel = self._get_tickets_button
elif sel_name == 'Back':
sel = self._back_button
elif sel_name == 'Scroll':
sel = self._scrollwidget
elif isinstance(sel_name, str) and sel_name.startswith('Tab:'):
- sel = self._tab_buttons[sel_name.split(':')[-1]]
+ try:
+ sel_tab_id = enum_by_value(self.TabID,
+ sel_name.split(':')[-1])
+ except ValueError:
+ sel_tab_id = self.TabID.CHARACTERS
+ sel = self._tab_row.tabs[sel_tab_id].button
else:
- sel = self._tab_buttons[current_tab]
- # if we were requested to show a tab, select it too..
+ sel = self._tab_row.tabs[current_tab].button
+
+ # If we were requested to show a tab, select it too..
if (self._show_tab is not None
- and self._show_tab in self._tab_buttons):
- sel = self._tab_buttons[self._show_tab]
+ and self._show_tab in self._tab_row.tabs):
+ sel = self._tab_row.tabs[self._show_tab].button
self._set_tab(current_tab)
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
- 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
- from bastd.ui.coop import browser
- from bastd.ui import mainmenu
+ from bastd.ui.coop.browser import CoopBrowserWindow
+ from bastd.ui.mainmenu import MainMenuWindow
self._save_state()
ba.containerwidget(edit=self._root_widget,
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(
+ 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(
+ 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/store/button.py b/assets/src/ba_data/python/bastd/ui/store/button.py
index 7807873d..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
@@ -212,12 +194,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 +208,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)
@@ -259,7 +243,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/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..62e8a2fd 100644
--- a/assets/src/ba_data/python/bastd/ui/tabs.py
+++ b/assets/src/ba_data/python/bastd/ui/tabs.py
@@ -1,28 +1,11 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-from typing import TYPE_CHECKING
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, TypeVar, Generic
import ba
@@ -30,67 +13,65 @@ if TYPE_CHECKING:
from typing import Any, Callable, Dict, Tuple, List, Sequence, Optional
-def create_tab_buttons(parent_widget: ba.Widget,
- tabs: List[Tuple[str, ba.Lstr]],
- pos: Sequence[float],
- size: Sequence[float],
- on_select_call: Callable[[Any], Any] = None,
- return_extra_info: bool = False) -> Dict[str, Any]:
- """(internal)"""
- # pylint: disable=too-many-locals
- tab_pos_v = pos[1]
- tab_buttons = {}
- tab_buttons_indexed = []
- tab_button_width = float(size[0]) / len(tabs)
-
- # add a bit more visual spacing as our buttons get narrower
- tab_spacing = (250.0 - tab_button_width) * 0.06
- positions = []
- sizes = []
- h = pos[0]
- for _i, tab in enumerate(tabs):
-
- def _tick_and_call(call: Optional[Callable[[Any], Any]],
- arg: Any) -> None:
- ba.playsound(ba.getsound('click01'))
- if call is not None:
- call(arg)
-
- pos = (h + tab_spacing * 0.5, tab_pos_v)
- size = (tab_button_width - tab_spacing, 50.0)
- positions.append(pos)
- sizes.append(size)
- btn = ba.buttonwidget(parent=parent_widget,
- position=pos,
- autoselect=True,
- button_type='tab',
- size=size,
- label=tab[1],
- enable_sound=False,
- on_activate_call=ba.Call(_tick_and_call,
- on_select_call, tab[0]))
- h += tab_button_width
- tab_buttons[tab[0]] = btn
- tab_buttons_indexed.append(btn)
- if return_extra_info:
- return {
- 'buttons': tab_buttons,
- 'buttons_indexed': tab_buttons_indexed,
- 'positions': positions,
- 'sizes': sizes
- }
- return tab_buttons
+@dataclass
+class Tab:
+ """Info for an individual tab in a TabRow"""
+ button: ba.Widget
+ position: Tuple[float, float]
+ size: Tuple[float, float]
-def update_tab_button_colors(tabs: Dict[str, ba.Widget],
- selected_tab: str) -> None:
- """(internal)"""
- for t_id, tbutton in list(tabs.items()):
- if t_id == selected_tab:
- ba.buttonwidget(edit=tbutton,
- color=(0.5, 0.4, 0.93),
- textcolor=(0.85, 0.75, 0.95)) # lit
- else:
- ba.buttonwidget(edit=tbutton,
- color=(0.52, 0.48, 0.63),
- textcolor=(0.65, 0.6, 0.7)) # unlit
+T = TypeVar('T')
+
+
+class TabRow(Generic[T]):
+ """Encapsulates a row of tab-styled buttons.
+
+ Tabs are indexed by id which is an arbitrary user-provided type.
+ """
+
+ def __init__(self,
+ parent: ba.Widget,
+ tabdefs: List[Tuple[T, ba.Lstr]],
+ pos: Tuple[float, float],
+ size: Tuple[float, float],
+ on_select_call: Callable[[T], None] = None) -> None:
+ if not tabdefs:
+ raise ValueError('At least one tab def is required')
+ self.tabs: Dict[T, Tab] = {}
+ tab_pos_v = pos[1]
+ tab_button_width = float(size[0]) / len(tabdefs)
+ tab_spacing = (250.0 - tab_button_width) * 0.06
+ h = pos[0]
+ for tab_id, tab_label in tabdefs:
+ pos = (h + tab_spacing * 0.5, tab_pos_v)
+ size = (tab_button_width - tab_spacing, 50.0)
+ btn = ba.buttonwidget(parent=parent,
+ position=pos,
+ autoselect=True,
+ button_type='tab',
+ size=size,
+ label=tab_label,
+ enable_sound=False,
+ on_activate_call=ba.Call(
+ self._tick_and_call, on_select_call,
+ tab_id))
+ h += tab_button_width
+ self.tabs[tab_id] = Tab(button=btn, position=pos, size=size)
+
+ def update_appearance(self, selected_tab_id: T) -> None:
+ """Update appearances to make the provided tab appear selected."""
+ for tab_id, tab in self.tabs.items():
+ if tab_id == selected_tab_id:
+ ba.buttonwidget(edit=tab.button,
+ color=(0.5, 0.4, 0.93),
+ textcolor=(0.85, 0.75, 0.95)) # lit
+ else:
+ ba.buttonwidget(edit=tab.button,
+ color=(0.52, 0.48, 0.63),
+ textcolor=(0.65, 0.6, 0.7)) # unlit
+
+ def _tick_and_call(self, call: Optional[Callable], arg: Any) -> None:
+ ba.playsound(ba.getsound('click01'))
+ if call is not None:
+ call(arg)
diff --git a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py
index 8af30be8..9f8450e7 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
@@ -43,26 +25,29 @@ 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.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,
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] = []
- ba.buttonwidget(
+ resetbtn = ba.buttonwidget(
parent=self.root_widget,
label=ba.Lstr(resource='settingsWindowAdvanced.resetText'),
autoselect=True,
@@ -93,20 +78,27 @@ class TeamNamesColorsWindow(popup.PopupWindow):
description=ba.Lstr(resource='nameText'),
editable=True,
padding=4))
- ba.buttonwidget(parent=self.root_widget,
- label=ba.Lstr(resource='cancelText'),
- autoselect=True,
- on_activate_call=self._on_cancel_press,
- size=(150, 50),
- position=(self._width * 0.5 - 200, 20))
- ba.buttonwidget(parent=self.root_widget,
- label=ba.Lstr(resource='saveText'),
- autoselect=True,
- on_activate_call=self._save,
- size=(150, 50),
- position=(self._width * 0.5 + 50, 20))
+ ba.widget(edit=self._color_text_fields[0],
+ down_widget=self._color_text_fields[1])
+ ba.widget(edit=self._color_text_fields[1],
+ up_widget=self._color_text_fields[0])
+ ba.widget(edit=self._color_text_fields[0], up_widget=resetbtn)
+
+ cancelbtn = ba.buttonwidget(parent=self.root_widget,
+ label=ba.Lstr(resource='cancelText'),
+ autoselect=True,
+ on_activate_call=self._on_cancel_press,
+ size=(150, 50),
+ position=(self._width * 0.5 - 200, 20))
+ okbtn = ba.buttonwidget(parent=self.root_widget,
+ label=ba.Lstr(resource='okText'),
+ autoselect=True,
+ on_activate_call=self._ok,
+ size=(150, 50),
+ position=(self._width * 0.5 + 50, 20))
ba.containerwidget(edit=self.root_widget,
selected_child=self._color_buttons[0])
+ ba.widget(edit=okbtn, left_widget=cancelbtn)
self._update()
def _color_click(self, i: int) -> None:
@@ -144,7 +136,7 @@ class TeamNamesColorsWindow(popup.PopupWindow):
ba.textwidget(edit=self._color_text_fields[i],
color=self._colors[i])
- def _save(self) -> None:
+ def _ok(self) -> None:
from ba.internal import DEFAULT_TEAM_COLORS, DEFAULT_TEAM_NAMES
cfg = ba.app.config
@@ -179,11 +171,10 @@ class TeamNamesColorsWindow(popup.PopupWindow):
if key in cfg:
del cfg[key]
else:
- cfg['Custom Team Names'] = tuple(new_names)
- cfg['Custom Team Colors'] = tuple(self._colors)
+ cfg['Custom Team Names'] = list(new_names)
+ cfg['Custom Team Colors'] = list(self._colors)
cfg.commit()
- ba.playsound(ba.getsound('gunCocking'))
self._transition_out()
def _transition_out(self, transition: str = 'out_scale') -> None:
diff --git a/assets/src/ba_data/python/bastd/ui/telnet.py b/assets/src/ba_data/python/bastd/ui/telnet.py
index 2d412947..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
@@ -34,10 +16,12 @@ class TelnetAccessRequestWindow(ba.Window):
height = 100
text = ba.Lstr(resource='telnetAccessText')
+ uiscale = ba.app.ui.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 3ecec8ff..12ed8b3a 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
@@ -43,14 +25,15 @@ 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-statements
ba.set_analytics_screen('Tournament Entry Window')
self._tournament_id = tournament_id
- self._tournament_info = (ba.app.tournament_info[self._tournament_id])
+ self._tournament_info = (
+ ba.app.accounts.tournament_info[self._tournament_id])
# Set a few vars depending on the tourney fee.
self._fee = self._tournament_info['fee']
@@ -69,7 +52,7 @@ class TournamentEntryWindow(popup.PopupWindow):
self._purchase_price_name = 'price.tournament_entry_1'
else:
if self._fee != 0:
- raise Exception('invalid fee: ' + str(self._fee))
+ raise ValueError('invalid fee: ' + str(self._fee))
self._purchase_name = 'tournament_entry_0'
self._purchase_price_name = 'price.tournament_entry_0'
@@ -77,15 +60,16 @@ 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.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
self._transitioning_out = False
self._tournament_activity = tournament_activity
self._width = 340
- self._height = 220
+ self._height = 225
bg_color = (0.5, 0.4, 0.6)
@@ -109,8 +93,8 @@ class TournamentEntryWindow(popup.PopupWindow):
x_offs = 0 if self._do_ad_btn else 85
self._cancel_button = ba.buttonwidget(parent=self.root_widget,
- position=(20, self._height - 30),
- size=(50, 50),
+ position=(20, self._height - 34),
+ size=(60, 60),
scale=0.5,
label='',
color=bg_color,
@@ -127,7 +111,7 @@ class TournamentEntryWindow(popup.PopupWindow):
v_align='center',
scale=0.6,
text=ba.Lstr(resource='tournamentEntryText'),
- maxwidth=200,
+ maxwidth=180,
color=(1, 1, 1, 0.4))
btn = self._pay_with_tickets_button = ba.buttonwidget(
@@ -230,20 +214,28 @@ class TournamentEntryWindow(popup.PopupWindow):
else:
self._pay_with_ad_btn = None
- self._get_tickets_button: Optional[ba.Widget]
- if not ba.app.toolbars:
- self._get_tickets_button = ba.buttonwidget(
- parent=self.root_widget,
- position=(self._width - 190 + 110, 15),
- autoselect=True,
- scale=0.6,
- size=(120, 60),
- textcolor=(0.2, 1, 0.2),
- label=ba.charstr(ba.SpecialChar.TICKET),
- color=(0.6, 0.4, 0.7),
- on_activate_call=self._on_get_tickets_press)
- else:
- self._get_tickets_button = None
+ self._get_tickets_button: Optional[ba.Widget] = None
+ self._ticket_count_text: Optional[ba.Widget] = None
+ if not ba.app.ui.use_toolbars:
+ if ba.app.allow_ticket_purchases:
+ self._get_tickets_button = ba.buttonwidget(
+ parent=self.root_widget,
+ position=(self._width - 190 + 125, self._height - 34),
+ autoselect=True,
+ scale=0.5,
+ size=(120, 60),
+ textcolor=(0.2, 1, 0.2),
+ label=ba.charstr(ba.SpecialChar.TICKET),
+ color=(0.65, 0.5, 0.8),
+ on_activate_call=self._on_get_tickets_press)
+ else:
+ self._ticket_count_text = ba.textwidget(
+ parent=self.root_widget,
+ scale=0.5,
+ position=(self._width - 190 + 125, self._height - 34),
+ color=(0.2, 1, 0.2),
+ h_align='center',
+ v_align='center')
self._seconds_remaining = None
@@ -253,20 +245,22 @@ 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
- self._time_remaining_text = ba.textwidget(parent=self.root_widget,
- position=(70 + xoffs, 23),
- size=(0, 0),
- h_align='center',
- v_align='center',
- text='-',
- scale=0.65,
- maxwidth=100,
- flatness=1.0,
- color=(0.7, 0.7, 0.7))
+ # xoffs = 104 if ba.app.ui.use_toolbars else 0
+ self._time_remaining_text = ba.textwidget(
+ parent=self.root_widget,
+ position=(self._width / 2, 28),
+ size=(0, 0),
+ h_align='center',
+ v_align='center',
+ text='-',
+ scale=0.65,
+ maxwidth=100,
+ flatness=1.0,
+ color=(0.7, 0.7, 0.7),
+ )
self._time_remaining_label_text = ba.textwidget(
parent=self.root_widget,
- position=(70 + xoffs, 40),
+ position=(self._width / 2, 45),
size=(0, 0),
h_align='center',
v_align='center',
@@ -280,13 +274,13 @@ class TournamentEntryWindow(popup.PopupWindow):
# If there seems to be a relatively-recent valid cached info for this
# tournament, use it. Otherwise we'll kick off a query ourselves.
- if (self._tournament_id in ba.app.tournament_info
- and ba.app.tournament_info[self._tournament_id]['valid'] and
- (ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) -
- ba.app.tournament_info[self._tournament_id]['timeReceived'] <
- 1000 * 60 * 5)):
+ if (self._tournament_id in ba.app.accounts.tournament_info and
+ ba.app.accounts.tournament_info[self._tournament_id]['valid']
+ and (ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) -
+ ba.app.accounts.tournament_info[self._tournament_id]
+ ['timeReceived'] < 1000 * 60 * 5)):
try:
- info = ba.app.tournament_info[self._tournament_id]
+ info = ba.app.accounts.tournament_info[self._tournament_id]
self._seconds_remaining = max(
0, info['timeRemaining'] - int(
(ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS)
@@ -310,12 +304,12 @@ class TournamentEntryWindow(popup.PopupWindow):
def _on_tournament_query_response(self, data: Optional[Dict[str,
Any]]) -> None:
- from ba.internal import cache_tournament_info
+ accounts = ba.app.accounts
self._running_query = False
if data is not None:
data = data['t'] # This used to be the whole payload.
- cache_tournament_info(data)
- self._seconds_remaining = ba.app.tournament_info[
+ accounts.cache_tournament_info(data)
+ self._seconds_remaining = accounts.tournament_info[
self._tournament_id]['timeRemaining']
self._have_valid_data = True
@@ -332,10 +326,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:
@@ -367,7 +358,8 @@ class TournamentEntryWindow(popup.PopupWindow):
self._running_query = True
# Grab the latest info on our tourney.
- self._tournament_info = ba.app.tournament_info[self._tournament_id]
+ self._tournament_info = ba.app.accounts.tournament_info[
+ self._tournament_id]
# If we don't have valid data always show a '-' for time.
if not self._have_valid_data:
@@ -433,9 +425,12 @@ class TournamentEntryWindow(popup.PopupWindow):
t_str = str(_ba.get_account_ticket_count())
except Exception:
t_str = '?'
- if self._get_tickets_button is not None:
+ if self._get_tickets_button:
ba.buttonwidget(edit=self._get_tickets_button,
label=ba.charstr(ba.SpecialChar.TICKET) + t_str)
+ if self._ticket_count_text:
+ ba.textwidget(edit=self._ticket_count_text,
+ text=ba.charstr(ba.SpecialChar.TICKET) + t_str)
def _launch(self) -> None:
if self._launched:
@@ -457,13 +452,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
+ ba.print_exception('Error restarting tournament activity.')
# If we had no existing activity (or were unable to restart it)
# launch a new session.
@@ -541,7 +537,6 @@ class TournamentEntryWindow(popup.PopupWindow):
self._launch()
def _on_pay_with_ad_press(self) -> None:
- from ba.internal import show_ad_2
# If we're already entering, ignore.
if self._entering:
@@ -563,8 +558,9 @@ class TournamentEntryWindow(popup.PopupWindow):
cur_time = ba.time(ba.TimeType.REAL)
if cur_time - self._last_ad_press_time > 5.0:
self._last_ad_press_time = cur_time
- show_ad_2('tournament_entry',
- on_completion_call=ba.WeakCall(self._on_ad_complete))
+ _ba.app.ads.show_ad_2('tournament_entry',
+ on_completion_call=ba.WeakCall(
+ self._on_ad_complete))
def _on_ad_complete(self, actually_showed: bool) -> None:
diff --git a/assets/src/ba_data/python/bastd/ui/tournamentscores.py b/assets/src/ba_data/python/bastd/ui/tournamentscores.py
index e4e6f622..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
@@ -53,14 +35,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.ui.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..4763172c 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
@@ -38,11 +20,11 @@ class TrophiesWindow(popup.PopupWindow):
position: Tuple[float, float],
data: Dict[str, Any],
scale: float = None):
- from ba.deprecated import get_resource
self._data = data
+ uiscale = ba.app.ui.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
@@ -93,7 +75,9 @@ class TrophiesWindow(popup.PopupWindow):
trophy_types = [['0a'], ['0b'], ['1'], ['2'], ['3'], ['4']]
sub_height = 40 + len(trophy_types) * incr
- eq_text = get_resource('coopSelectWindow.powerRankingPointsEqualsText')
+ eq_text = ba.Lstr(
+ resource='coopSelectWindow.powerRankingPointsEqualsText').evaluate(
+ )
self._subcontainer = ba.containerwidget(parent=self._scrollwidget,
size=(sub_width, sub_height),
@@ -101,25 +85,27 @@ class TrophiesWindow(popup.PopupWindow):
total_pts = 0
- multi_txt = get_resource('coopSelectWindow.powerRankingPointsMultText')
+ multi_txt = ba.Lstr(
+ resource='coopSelectWindow.powerRankingPointsMultText').evaluate()
total_pts += self._create_trophy_type_widgets(eq_text, incr, multi_txt,
sub_height, sub_width,
trophy_types)
- ba.textwidget(parent=self._subcontainer,
- position=(sub_width * 1.0,
- sub_height - 20 - incr * len(trophy_types)),
- maxwidth=sub_width * 0.5,
- scale=0.7,
- color=(0.7, 0.8, 1.0),
- flatness=1.0,
- shadow=0.0,
- text=get_resource('coopSelectWindow.totalText') + ' ' +
- eq_text.replace('${NUMBER}', str(total_pts)),
- size=(0, 0),
- h_align='right',
- v_align='center')
+ ba.textwidget(
+ parent=self._subcontainer,
+ position=(sub_width * 1.0,
+ sub_height - 20 - incr * len(trophy_types)),
+ maxwidth=sub_width * 0.5,
+ scale=0.7,
+ color=(0.7, 0.8, 1.0),
+ flatness=1.0,
+ shadow=0.0,
+ text=ba.Lstr(resource='coopSelectWindow.totalText').evaluate() +
+ ' ' + eq_text.replace('${NUMBER}', str(total_pts)),
+ size=(0, 0),
+ h_align='right',
+ v_align='center')
def _create_trophy_type_widgets(self, eq_text: str, incr: int,
multi_txt: str, sub_height: int,
diff --git a/assets/src/ba_data/python/bastd/ui/url.py b/assets/src/ba_data/python/bastd/ui/url.py
index 3f287dcc..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
@@ -34,14 +16,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.ui.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,12 +51,12 @@ 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),
- color=ba.app.title_color,
+ color=ba.app.ui.title_color,
h_align='center',
v_align='center',
text=ba.Lstr(resource='directBrowserToURLText'),
@@ -83,7 +66,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 cc09b297..b27a381a 100644
--- a/assets/src/ba_data/python/bastd/ui/watch.py
+++ b/assets/src/ba_data/python/bastd/ui/watch.py
@@ -1,28 +1,11 @@
-# Copyright (c) 2011-2020 Eric Froemling
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
import os
+from enum import Enum
from typing import TYPE_CHECKING, cast
import _ba
@@ -35,12 +18,17 @@ if TYPE_CHECKING:
class WatchWindow(ba.Window):
"""Window for watching replays."""
+ class TabID(Enum):
+ """Our available tab types."""
+ MY_REPLAYS = 'my_replays'
+ TEST_TAB = 'test_tab'
+
def __init__(self,
transition: Optional[str] = 'in_right',
origin_widget: ba.Widget = None):
# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
- from bastd.ui import tabs
+ from bastd.ui.tabs import TabRow
ba.set_analytics_screen('Watch Window')
scale_origin: Optional[Tuple[float, float]]
if origin_widget is not None:
@@ -50,7 +38,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
@@ -60,23 +48,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)
- self._current_tab: Optional[str] = None
- extra_top = 20 if ba.app.small_ui else 0
+ 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
+ 670 if uiscale is ba.UIScale.MEDIUM else 800)
+ self._current_tab: Optional[WatchWindow.TabID] = None
+ 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.ui.use_toolbars:
ba.containerwidget(edit=self._root_widget,
on_cancel_call=self._back)
self._back_button = None
@@ -99,39 +89,43 @@ 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',
text=ba.Lstr(resource=self._r + '.titleText'),
maxwidth=400)
- tabs_def = [('my_replays',
- ba.Lstr(resource=self._r + '.myReplaysText'))]
+ tabdefs = [
+ (self.TabID.MY_REPLAYS,
+ ba.Lstr(resource=self._r + '.myReplaysText')),
+ # (self.TabID.TEST_TAB, ba.Lstr(value='Testing')),
+ ]
scroll_buffer_h = 130 + 2 * x_inset
tab_buffer_h = 750 + 2 * x_inset
- self._tab_buttons = tabs.create_tab_buttons(
- self._root_widget,
- tabs_def,
- pos=(tab_buffer_h * 0.5, self._height - 130),
- size=(self._width - tab_buffer_h, 50),
- on_select_call=self._set_tab)
+ self._tab_row = TabRow(self._root_widget,
+ tabdefs,
+ pos=(tab_buffer_h * 0.5, self._height - 130),
+ size=(self._width - tab_buffer_h, 50),
+ on_select_call=self._set_tab)
- if ba.app.toolbars:
- ba.widget(edit=self._tab_buttons[tabs_def[-1][0]],
+ if ba.app.ui.use_toolbars:
+ first_tab = self._tab_row.tabs[tabdefs[0][0]]
+ last_tab = self._tab_row.tabs[tabdefs[-1][0]]
+ ba.widget(edit=last_tab.button,
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]],
+ ba.widget(edit=first_tab.button,
up_widget=bbtn,
left_widget=bbtn)
self._scroll_width = self._width - scroll_buffer_h
self._scroll_height = self._height - 180
- # not actually using a scroll widget anymore; just an image
+ # Not actually using a scroll widget anymore; just an image.
scroll_left = (self._width - self._scroll_width) * 0.5
scroll_bottom = self._height - self._scroll_height - 79 - 48
buffer_h = 10
@@ -147,21 +141,21 @@ class WatchWindow(ba.Window):
self._restore_state()
- def _set_tab(self, tab: str) -> None:
+ def _set_tab(self, tab_id: TabID) -> None:
# pylint: disable=too-many-locals
- from bastd.ui import tabs
- if self._current_tab == tab:
+ if self._current_tab == tab_id:
return
- self._current_tab = tab
+ self._current_tab = tab_id
- # We wanna preserve our current tab between runs.
+ # Preserve our current tab between runs.
cfg = ba.app.config
- cfg['Watch Tab'] = tab
+ cfg['Watch Tab'] = tab_id.value
cfg.commit()
# Update tab colors based on which is selected.
- tabs.update_tab_button_colors(self._tab_buttons, tab)
+ # tabs.update_tab_button_colors(self._tab_buttons, tab)
+ self._tab_row.update_appearance(tab_id)
if self._tab_container:
self._tab_container.delete()
@@ -172,12 +166,13 @@ class WatchWindow(ba.Window):
# switching to a different tab
self._tab_data = {}
- if tab == 'my_replays':
+ uiscale = ba.app.ui.uiscale
+ if tab_id is self.TabID.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,
@@ -185,7 +180,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,
@@ -202,19 +197,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),
@@ -226,8 +222,8 @@ class WatchWindow(ba.Window):
text_scale=tscl,
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:
+ ba.widget(edit=btn1, up_widget=self._tab_row.tabs[tab_id].button)
+ 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
@@ -261,13 +257,17 @@ 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,
left_widget=btn1,
- up_widget=self._tab_buttons[tab])
- ba.widget(edit=self._tab_buttons[tab], down_widget=scrlw)
+ up_widget=self._tab_row.tabs[tab_id].button)
+ ba.widget(edit=self._tab_row.tabs[tab_id].button,
+ down_widget=scrlw)
self._my_replay_selected = None
self._refresh_my_replays()
@@ -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)
@@ -308,8 +309,10 @@ class WatchWindow(ba.Window):
return
c_width = 600
c_height = 250
+ uiscale = ba.app.ui.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)
@@ -363,15 +366,16 @@ class WatchWindow(ba.Window):
new_name_raw = cast(
str, ba.textwidget(query=self._my_replay_rename_text))
new_name = new_name_raw + '.brp'
- # ignore attempts to change it to what it already is
- # (or what it looks like to the user)
+
+ # Ignore attempts to change it to what it already is
+ # (or what it looks like to the user).
if (replay != new_name
and self._get_replay_display_name(replay) != new_name_raw):
old_name_full = (_ba.get_replays_dir() + '/' +
replay).encode('utf-8')
new_name_full = (_ba.get_replays_dir() + '/' +
new_name).encode('utf-8')
- # false alarm; ba.textwidget can return non-None val
+ # False alarm; ba.textwidget can return non-None val.
# pylint: disable=unsupported-membership-test
if os.path.exists(new_name_full):
ba.playsound(ba.getsound('error'))
@@ -391,11 +395,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 +433,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
@@ -444,11 +450,12 @@ class WatchWindow(ba.Window):
t_scale = 1.6
try:
names = os.listdir(_ba.get_replays_dir())
- # ignore random other files in there..
+
+ # Ignore random other files in there.
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
@@ -469,60 +476,68 @@ class WatchWindow(ba.Window):
corner_scale=t_scale,
maxwidth=(self._my_replays_scroll_width / t_scale) * 0.93)
if i == 0:
- ba.widget(edit=txt, up_widget=self._tab_buttons['my_replays'])
+ ba.widget(
+ edit=txt,
+ up_widget=self._tab_row.tabs[self.TabID.MY_REPLAYS].button)
def _save_state(self) -> None:
try:
sel = self._root_widget.get_selected_child()
+ selected_tab_ids = [
+ tab_id for tab_id, tab in self._tab_row.tabs.items()
+ if sel == tab.button
+ ]
if sel == self._back_button:
sel_name = 'Back'
- elif sel in list(self._tab_buttons.values()):
- sel_name = 'Tab:' + list(self._tab_buttons.keys())[list(
- self._tab_buttons.values()).index(sel)]
+ elif selected_tab_ids:
+ assert len(selected_tab_ids) == 1
+ sel_name = f'Tab:{selected_tab_ids[0].value}'
elif sel == self._tab_container:
sel_name = 'TabContainer'
else:
- raise Exception('unrecognized selection')
- ba.app.window_states[self.__class__.__name__] = {
- 'sel_name': sel_name,
- 'tab': self._current_tab
- }
+ raise ValueError(f'unrecognized selection {sel}')
+ ba.app.ui.window_states[type(self)] = {'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:
+ from efro.util import enum_by_value
try:
+ sel: Optional[ba.Widget]
+ sel_name = ba.app.ui.window_states.get(type(self),
+ {}).get('sel_name')
+ assert isinstance(sel_name, (str, type(None)))
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
- if current_tab is None or current_tab not in self._tab_buttons:
- current_tab = 'my_replays'
+ current_tab = enum_by_value(self.TabID,
+ ba.app.config.get('Watch Tab'))
+ except ValueError:
+ current_tab = self.TabID.MY_REPLAYS
self._set_tab(current_tab)
+
if sel_name == 'Back':
sel = self._back_button
elif sel_name == 'TabContainer':
sel = self._tab_container
elif isinstance(sel_name, str) and sel_name.startswith('Tab:'):
- sel = self._tab_buttons[sel_name.split(':')[-1]]
+ try:
+ sel_tab_id = enum_by_value(self.TabID,
+ sel_name.split(':')[-1])
+ except ValueError:
+ sel_tab_id = self.TabID.MY_REPLAYS
+ sel = self._tab_row.tabs[sel_tab_id].button
else:
if self._tab_container is not None:
sel = self._tab_container
else:
- sel = self._tab_buttons[current_tab]
+ sel = self._tab_row.tabs[current_tab].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}.')
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/server/README.txt b/assets/src/server/README.txt
index afc5f770..78a1237a 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:
@@ -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"
+- Server binaries are currently compiled against Ubuntu 20 LTS.
Raspberry Pi:
- The server binary was compiled on a Raspberry Pi 4 running Raspbian Buster.
@@ -25,7 +23,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/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py
index 8ce43e83..d2a7c53f 100755
--- a/assets/src/server/ballisticacore_server.py
+++ b/assets/src/server/ballisticacore_server.py
@@ -1,56 +1,58 @@
-#!/usr/bin/env python3.7
-# Copyright (c) 2011-2020 Eric Froemling
+#!/usr/bin/env python3.8
+# Released under the MIT License. See LICENSE for details.
#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION 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
-import sys
-import os
import json
+import os
+import signal
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 make use of the bacommon and efro packages as well as site-packages
-# included with our bundled Ballistica dist.
+# included with our bundled Ballistica dist, so we need to add those paths
+# before we import them.
sys.path += [
- str(Path(os.getcwd(), 'dist', 'ba_data', 'python')),
- str(Path(os.getcwd(), 'dist', 'ba_data', 'python-site-packages'))
+ str(Path(Path(__file__).parent, 'dist', 'ba_data', 'python')),
+ str(Path(Path(__file__).parent, 'dist', 'ba_data', 'python-site-packages'))
]
-from efro.terminal import Clr
+from bacommon.servermanager import ServerConfig, StartServerModeCommand
+from efro.dataclasses import dataclass_from_dict, dataclass_validate
from efro.error import CleanError
-from efro.dataclasses import dataclass_assign, dataclass_validate
-from bacommon.servermanager import (ServerConfig, StartServerModeCommand)
+from efro.terminal import Clr
if TYPE_CHECKING:
from typing import Optional, List, Dict, Union, Tuple
from types import FrameType
from bacommon.servermanager import ServerCommand
-# 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.2'
+
+# Version history:
+# 1.2:
+# Added optional --help arg
+# Added --config arg for setting config path and --root for ba_root path
+# Added noninteractive mode and --interactive/--noninteractive args to
+# explicitly specify
+# Added explicit control for auto-restart: --no-auto-restart
+# Config file is now reloaded each time server binary is restarted; no more
+# need to bring down server wrapper to pick up changes
+# Now automatically restarts server binary when config file is modified
+# (use --no-config-auto-restart to disable that behavior)
+# 1.1.1:
+# Switched config reading to use efro.dataclasses.dataclass_from_dict()
+# 1.1.0:
+# Added shutdown command
+# Changed restart to default to immediate=True
+# Added clean_exit_minutes, unclean_exit_minutes, and idle_exit_minutes
+# 1.0.0:
+# Initial release
class ServerManagerApp:
@@ -60,20 +62,42 @@ class ServerManagerApp:
managing BallisticaCore operating in server mode.
"""
+ # How many seconds we wait after asking our subprocess to do an immediate
+ # shutdown before bringing down the hammer.
+ IMMEDIATE_SHUTDOWN_TIME_LIMIT = 5.0
+
def __init__(self) -> None:
- try:
- self._config = self._load_config()
- except Exception as exc:
- raise CleanError(f'Error loading config: {exc}')
+ self._config_path = 'config.yaml'
+ self._user_provided_config_path = False
+ self._config = ServerConfig()
+ self._ba_root_path = os.path.abspath('dist/ba_root')
+ self._interactive = sys.stdin.isatty()
+ self._wrapper_shutdown_desired = False
self._done = False
- self._process_commands: List[Union[str, ServerCommand]] = []
- self._process_commands_lock = Lock()
- self._restart_minutes: Optional[float] = 360.0
- self._running_interactive = False
- self._process: Optional[subprocess.Popen[bytes]] = None
- self._process_launch_time: Optional[float] = None
- self._process_sent_auto_restart = False
- self._process_thread: Optional[Thread] = None
+ self._subprocess_commands: List[Union[str, ServerCommand]] = []
+ self._subprocess_commands_lock = Lock()
+ self._subprocess_force_kill_time: Optional[float] = None
+ self._auto_restart = True
+ self._config_auto_restart = True
+ self._config_mtime: Optional[float] = None
+ self._last_config_mtime_check_time: Optional[float] = None
+ self._should_report_subprocess_error = False
+ self._running = False
+ self._interpreter_start_time: Optional[float] = None
+ self._subprocess: Optional[subprocess.Popen[bytes]] = None
+ self._subprocess_launch_time: Optional[float] = None
+ self._subprocess_sent_config_auto_restart = False
+ self._subprocess_sent_clean_exit = False
+ self._subprocess_sent_unclean_exit = False
+ self._subprocess_thread: Optional[Thread] = None
+ self._subprocess_exited_cleanly: Optional[bool] = None
+
+ # This may override the above defaults.
+ self._parse_command_line_args()
+
+ # Do an initial config-load. If the config is invalid at this point
+ # we can cleanly die (we're more lenient later on reloads).
+ self.load_config(strict=True, print_confirmation=False)
@property
def config(self) -> ServerConfig:
@@ -85,42 +109,87 @@ class ServerManagerApp:
dataclass_validate(value)
self._config = value
- @property
- def restart_minutes(self) -> Optional[float]:
- """The time between automatic server restarts.
+ def _prerun(self) -> None:
+ """Common code at the start of any run."""
- Restarting the server periodically can minimize the effect of
- memory leaks or other built-up cruft.
- """
- return self._restart_minutes
+ # Make sure we don't call run multiple times.
+ if self._running:
+ raise RuntimeError('Already running.')
+ self._running = True
- def run_interactive(self) -> None:
- """Run the app loop to completion."""
- import code
- import signal
-
- if self._running_interactive:
- raise RuntimeError('Already running interactively.')
- self._running_interactive = True
-
- # Print basic usage info in interactive mode.
- if sys.stdin.isatty():
- print(f'{Clr.CYN}{Clr.BLD}BallisticaCore server'
- f' manager {VERSION_STR}'
- f' starting up...{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}')
+ dbgstr = 'debug' if __debug__ else 'opt'
+ print(
+ f'{Clr.CYN}{Clr.BLD}BallisticaCore server manager {VERSION_STR}'
+ f' starting up ({dbgstr} mode)...{Clr.RST}',
+ flush=True)
# Python will handle SIGINT for us (as KeyboardInterrupt) but we
# need to register a SIGTERM handler so we have a chance to clean
- # up our child-process when someone tells us to die. (and avoid
+ # up our subprocess when someone tells us to die. (and avoid
# zombie processes)
signal.signal(signal.SIGTERM, self._handle_term_signal)
+ # During a run, we make the assumption that cwd is the dir
+ # containing this script, so make that so. Up until now that may
+ # not be the case (we support being called from any location).
+ os.chdir(os.path.abspath(os.path.dirname(__file__)))
+
# Fire off a background thread to wrangle our server binaries.
- self._process_thread = Thread(target=self._bg_thread_main)
- self._process_thread.start()
+ self._subprocess_thread = Thread(target=self._bg_thread_main)
+ self._subprocess_thread.start()
+
+ def _postrun(self) -> None:
+ """Common code at the end of any run."""
+ print(f'{Clr.CYN}Server manager shutting down...{Clr.RST}', flush=True)
+
+ assert self._subprocess_thread is not None
+ if self._subprocess_thread.is_alive():
+ print(f'{Clr.CYN}Waiting for subprocess exit...{Clr.RST}',
+ flush=True)
+
+ # Mark ourselves as shutting down and wait for the process to wrap up.
+ self._done = True
+ self._subprocess_thread.join()
+
+ # If there's a server error we should care about, exit the
+ # entire wrapper uncleanly.
+ if self._should_report_subprocess_error:
+ raise CleanError('Server subprocess exited uncleanly.')
+
+ def run(self) -> None:
+ """Do the thing."""
+ if self._interactive:
+ self._run_interactive()
+ else:
+ self._run_noninteractive()
+
+ def _run_noninteractive(self) -> None:
+ """Run the app loop to completion noninteractively."""
+ self._prerun()
+ try:
+ while True:
+ time.sleep(1.234)
+ except KeyboardInterrupt:
+ # Gracefully bow out if we kill ourself via keyboard.
+ pass
+ except SystemExit:
+ # We get this from the builtin quit(), our signal handler, etc.
+ # Need to catch this so we can clean up, otherwise we'll be
+ # left in limbo with our process thread still running.
+ pass
+ self._postrun()
+
+ def _run_interactive(self) -> None:
+ """Run the app loop to completion interactively."""
+ import code
+ self._prerun()
+
+ # Print basic usage info for interactive mode.
+ print(
+ f"{Clr.CYN}Interactive mode enabled; use the 'mgr' object"
+ f' to interact with the server.\n'
+ f"Type 'help(mgr)' for more information.{Clr.RST}",
+ flush=True)
context = {'__name__': '__console__', '__doc__': None, 'mgr': self}
@@ -130,39 +199,31 @@ class ServerManagerApp:
# Now just sit in an interpreter.
# TODO: make it possible to use IPython if the user has it available.
try:
+ self._interpreter_start_time = time.time()
code.interact(local=context, banner='', exitmsg='')
except SystemExit:
- # We get this from the builtin quit(), etc.
+ # We get this from the builtin quit(), our signal handler, etc.
# Need to catch this so we can clean up, otherwise we'll be
# left in limbo with our process thread still running.
pass
except BaseException as exc:
- # Installing Python 3.7 on Ubuntu 18 can lead to this error;
- # inform the user how to fix it.
- if "No module named 'apt_pkg'" in str(exc):
- print(f'{Clr.SRED}Error: Your Python environment needs to'
- ' be fixed (apt_pkg cannot be found).\n'
- f'See the final step in the Linux instructions here:\n'
- f' https://github.com/efroemling/ballistica/'
- f'wiki/Getting-Started#linux{Clr.RST}')
- else:
- print(f'{Clr.SRED}Unexpected interpreter exception:'
- f' {exc} ({type(exc)}){Clr.RST}')
+ print(
+ f'{Clr.SRED}Unexpected interpreter exception:'
+ f' {exc} ({type(exc)}){Clr.RST}',
+ flush=True)
- # Mark ourselves as shutting down and wait for the process to wrap up.
- self._done = True
- self._process_thread.join()
+ self._postrun()
def cmd(self, statement: str) -> None:
- """Exec a Python command on the current running server child-process.
+ """Exec a Python command on the current running server subprocess.
Note that commands are executed asynchronously and no status or
return value is accessible from this manager app.
"""
if not isinstance(statement, str):
raise TypeError(f'Expected a string arg; got {type(statement)}')
- with self._process_commands_lock:
- self._process_commands.append(statement)
+ with self._subprocess_commands_lock:
+ self._subprocess_commands.append(statement)
self._block_for_command_completion()
def _block_for_command_completion(self) -> None:
@@ -172,8 +233,8 @@ class ServerManagerApp:
# it. In the future we can perhaps add a proper 'command port'
# interface for proper blocking two way communication.
while True:
- with self._process_commands_lock:
- if not self._process_commands:
+ with self._subprocess_commands_lock:
+ if not self._subprocess_commands:
break
time.sleep(0.1)
@@ -225,35 +286,245 @@ class ServerManagerApp:
self._enqueue_server_command(
KickCommand(client_id=client_id, ban_time=ban_time))
- def restart(self, immediate: bool = False) -> None:
- """Restart the server child-process.
+ def restart(self, immediate: bool = True) -> None:
+ """Restart the server subprocess.
- This can be necessary for some config changes to take effect.
- By default, the server will restart at the next good transition
- point (end of a series, etc) but passing immediate=True will restart
- it immediately.
+ By default, the current server process will exit immediately.
+ If 'immediate' is passed as False, however, it will instead exit at
+ the next clean transition point (the end of a series, etc).
"""
from bacommon.servermanager import ShutdownCommand, ShutdownReason
self._enqueue_server_command(
ShutdownCommand(reason=ShutdownReason.RESTARTING,
immediate=immediate))
- def _load_config(self) -> ServerConfig:
- user_config_path = 'config.yaml'
+ # If we're asking for an immediate restart but don't get one within
+ # the grace period, bring down the hammer.
+ if immediate:
+ self._subprocess_force_kill_time = (
+ time.time() + self.IMMEDIATE_SHUTDOWN_TIME_LIMIT)
- # Start with a default config, and if there is a config.yaml,
- # assign whatever is contained within.
- config = ServerConfig()
- if os.path.exists(user_config_path):
- import yaml
- with open(user_config_path) as infile:
- user_config = yaml.safe_load(infile.read())
+ def shutdown(self, immediate: bool = True) -> None:
+ """Shut down the server subprocess and exit the wrapper.
- # An empty config file will yield None, and that's ok.
- if user_config is not None:
- dataclass_assign(config, user_config)
+ By default, the current server process will exit immediately.
+ If 'immediate' is passed as False, however, it will instead exit at
+ the next clean transition point (the end of a series, etc).
+ """
+ from bacommon.servermanager import ShutdownCommand, ShutdownReason
+ self._enqueue_server_command(
+ ShutdownCommand(reason=ShutdownReason.NONE, immediate=immediate))
- return config
+ # An explicit shutdown means we know to bail completely once this
+ # subprocess completes.
+ self._wrapper_shutdown_desired = True
+
+ # If we're asking for an immediate shutdown but don't get one within
+ # the grace period, bring down the hammer.
+ if immediate:
+ self._subprocess_force_kill_time = (
+ time.time() + self.IMMEDIATE_SHUTDOWN_TIME_LIMIT)
+
+ def _parse_command_line_args(self) -> None:
+ """Parse command line args."""
+ # pylint: disable=too-many-branches
+
+ i = 1
+ argc = len(sys.argv)
+ did_set_interactive = False
+ while i < argc:
+ arg = sys.argv[i]
+ if arg == '--help':
+ self.print_help()
+ sys.exit(0)
+ elif arg == '--config':
+ if i + 1 >= argc:
+ raise CleanError('Expected a config path as next arg.')
+ path = sys.argv[i + 1]
+ if not os.path.exists(path):
+ raise CleanError(
+ f"Supplied path does not exist: '{path}'.")
+ # We need an abs path because we may be in a different
+ # cwd currently than we will be during the run.
+ self._config_path = os.path.abspath(path)
+ self._user_provided_config_path = True
+ i += 2
+ elif arg == '--root':
+ if i + 1 >= argc:
+ raise CleanError('Expected a path as next arg.')
+ path = sys.argv[i + 1]
+ # Unlike config_path, this one doesn't have to exist now.
+ # We do however need an abs path because we may be in a
+ # different cwd currently than we will be during the run.
+ self._ba_root_path = os.path.abspath(path)
+ i += 2
+ elif arg == '--interactive':
+ if did_set_interactive:
+ raise CleanError('interactive/noninteractive can only'
+ ' be specified once.')
+ self._interactive = True
+ did_set_interactive = True
+ i += 1
+ elif arg == '--noninteractive':
+ if did_set_interactive:
+ raise CleanError('interactive/noninteractive can only'
+ ' be specified once.')
+ self._interactive = False
+ did_set_interactive = True
+ i += 1
+ elif arg == '--no-auto-restart':
+ self._auto_restart = False
+ i += 1
+ elif arg == '--no-config-auto-restart':
+ self._config_auto_restart = False
+ i += 1
+ else:
+ raise CleanError(f"Invalid arg: '{arg}'.")
+
+ @classmethod
+ def _par(cls, txt: str) -> str:
+ """Spit out a pretty paragraph for our help text."""
+ import textwrap
+ ind = ' ' * 2
+ out = textwrap.fill(txt, 80, initial_indent=ind, subsequent_indent=ind)
+ return f'{out}\n'
+
+ @classmethod
+ def print_help(cls) -> None:
+ """Print app help."""
+ filename = os.path.basename(__file__)
+ out = (
+ f'{Clr.BLD}{filename} usage:{Clr.RST}\n' + cls._par(
+ 'This script handles configuring, launching, re-launching,'
+ ' and otherwise managing BallisticaCore operating'
+ ' in server mode. It can be run with no arguments, but'
+ ' accepts the following optional ones:') + f'\n'
+ f'{Clr.BLD}--help:{Clr.RST}\n'
+ f' Show this help.\n'
+ f'\n'
+ f'{Clr.BLD}--config [path]{Clr.RST}\n' + cls._par(
+ 'Set the config file read by the server script. The config'
+ ' file contains most options for what kind of game to host.'
+ ' It should be in yaml format. Note that yaml is backwards'
+ ' compatible with json so you can just write json if you'
+ ' want to. If not specified, the script will look for a'
+ ' file named \'config.yaml\' in the same directory as the'
+ ' script.') + '\n'
+ f'{Clr.BLD}--root [path]{Clr.RST}\n' + cls._par(
+ 'Set the ballistica root directory. This is where the server'
+ ' binary will read and write its caches, state files,'
+ ' downloaded assets, etc. It needs to be a writable'
+ ' directory. If not specified, the script will use the'
+ ' \'dist/ba_root\' directory relative to itself.') + '\n'
+ f'{Clr.BLD}--interactive{Clr.RST}\n'
+ f'{Clr.BLD}--noninteractive{Clr.RST}\n' + cls._par(
+ 'Specify whether the script should run interactively.'
+ ' In interactive mode, the script creates a Python interpreter'
+ ' and reads commands from stdin, allowing for live interaction'
+ ' with the server. The server script will then exit when '
+ 'end-of-file is reached in stdin. Noninteractive mode creates'
+ ' no interpreter and is more suited to being run in automated'
+ ' scenarios. By default, interactive mode will be used if'
+ ' a terminal is detected and noninteractive mode otherwise.') +
+ '\n'
+ f'{Clr.BLD}--no-auto-restart{Clr.RST}\n' +
+ cls._par('Auto-restart is enabled by default, which means the'
+ ' server manager will restart the server binary whenever'
+ ' it exits (even when uncleanly). Disabling auto-restart'
+ ' will cause the server manager to instead exit after a'
+ ' single run and also to return error codes if the'
+ ' server binary did so.') + '\n'
+ f'{Clr.BLD}--no-config-auto-restart{Clr.RST}\n' + cls._par(
+ 'By default, when auto-restart is enabled, the server binary'
+ ' will be automatically restarted if changes to the server'
+ ' config file are detected. This disables that behavior.'))
+ print(out)
+
+ def load_config(self, strict: bool, print_confirmation: bool) -> None:
+ """Load the config.
+
+ If strict is True, errors will propagate upward.
+ Otherwise, warnings will be printed and repeated attempts will be
+ made to load the config. Eventually the function will give up
+ and leave the existing config as-is.
+ """
+ retry_seconds = 3
+ maxtries = 11
+ for trynum in range(maxtries):
+ try:
+ self._config = self._load_config_from_file(
+ print_confirmation=print_confirmation)
+ return
+ except Exception as exc:
+ if strict:
+ raise CleanError(
+ f'Error loading config file:\n{exc}') from exc
+ print(f'{Clr.RED}Error loading config file:\n{exc}.{Clr.RST}',
+ flush=True)
+ if trynum == maxtries - 1:
+ print(
+ f'{Clr.RED}Max-tries reached; giving up.'
+ f' Existing config values will be used.{Clr.RST}',
+ flush=True)
+ break
+ print(
+ f'{Clr.CYN}Please correct the error.'
+ f' Will re-attempt load in {retry_seconds}'
+ f' seconds. (attempt {trynum+1} of'
+ f' {maxtries-1}).{Clr.RST}',
+ flush=True)
+
+ for _j in range(retry_seconds):
+ # If the app is trying to die, drop what we're doing.
+ if self._done:
+ return
+ time.sleep(1)
+
+ def _load_config_from_file(self, print_confirmation: bool) -> ServerConfig:
+
+ out: Optional[ServerConfig] = None
+
+ if not os.path.exists(self._config_path):
+
+ # Special case:
+ # If the user didn't specify a particular config file, allow
+ # gracefully falling back to defaults if the default one is
+ # missing.
+ if not self._user_provided_config_path:
+ if print_confirmation:
+ print(
+ f'{Clr.YLW}Default config file not found'
+ f' (\'{self._config_path}\'); using default'
+ f' settings.{Clr.RST}',
+ flush=True)
+ self._config_mtime = None
+ self._last_config_mtime_check_time = time.time()
+ return ServerConfig()
+
+ # Don't be so lenient if the user pointed us at one though.
+ raise RuntimeError(
+ f"Config file not found: '{self._config_path}'.")
+
+ import yaml
+ with open(self._config_path) as infile:
+ user_config_raw = yaml.safe_load(infile.read())
+
+ # An empty config file will yield None, and that's ok.
+ if user_config_raw is not None:
+ out = dataclass_from_dict(ServerConfig, user_config_raw)
+
+ # Update our known mod-time since we know it exists.
+ self._config_mtime = Path(self._config_path).stat().st_mtime
+ self._last_config_mtime_check_time = time.time()
+
+ # Go with defaults if we weren't able to load anything.
+ if out is None:
+ out = ServerConfig()
+
+ if print_confirmation:
+ print(f'{Clr.CYN}Valid server config file loaded.{Clr.RST}',
+ flush=True)
+ return out
def _enable_tab_completion(self, locs: Dict) -> None:
"""Enable tab-completion on platforms where available (linux/mac)."""
@@ -274,41 +545,100 @@ class ServerManagerApp:
def _handle_term_signal(self, sig: int, frame: FrameType) -> None:
"""Handle signals (will always run in the main thread)."""
del sig, frame # Unused.
- raise SystemExit()
+ sys.exit(1 if self._should_report_subprocess_error else 0)
def _run_server_cycle(self) -> None:
- """Spin up the server child-process and run it until exit."""
+ """Spin up the server subprocess and run it until exit."""
- self._prep_process_environment()
+ # Reload our config, and update our overall behavior based on it.
+ # We do non-strict this time to give the user repeated attempts if
+ # if they mess up while modifying the config on the fly.
+ self.load_config(strict=False, print_confirmation=True)
+
+ self._prep_subprocess_environment()
# Launch the binary and grab its stdin;
# we'll use this to feed it commands.
- self._process_launch_time = time.time()
+ self._subprocess_launch_time = time.time()
# Set an environment var so the server process knows its being
# run under us. This causes it to ignore ctrl-c presses and other
# slight behavior tweaks. Hmm; should this be an argument instead?
os.environ['BA_SERVER_WRAPPER_MANAGED'] = '1'
- print(f'{Clr.CYN}Launching server child-process...{Clr.RST}')
+ print(f'{Clr.CYN}Launching server subprocess...{Clr.RST}', flush=True)
binary_name = ('ballisticacore_headless.exe'
if os.name == 'nt' else './ballisticacore_headless')
- self._process = subprocess.Popen([binary_name, '-cfgdir', 'ba_root'],
- stdin=subprocess.PIPE,
- cwd='dist')
+ assert self._ba_root_path is not None
+ self._subprocess = None
+
+ # Launch!
+ try:
+ self._subprocess = subprocess.Popen(
+ [binary_name, '-cfgdir', self._ba_root_path],
+ stdin=subprocess.PIPE,
+ cwd='dist')
+ except Exception as exc:
+ self._subprocess_exited_cleanly = False
+ print(
+ f'{Clr.RED}Error launching server subprocess: {exc}{Clr.RST}',
+ flush=True)
# Do the thing.
- # No matter how this ends up, make sure the process is dead after.
try:
- self._run_process_until_exit()
- finally:
- self._kill_process()
+ self._run_subprocess_until_exit()
+ except Exception as exc:
+ print(f'{Clr.RED}Error running server subprocess: {exc}{Clr.RST}',
+ flush=True)
- def _prep_process_environment(self) -> None:
+ self._kill_subprocess()
+
+ assert self._subprocess_exited_cleanly is not None
+
+ # EW: it seems that if we die before the main thread has fully started
+ # up the interpreter, its possible that it will not break out of its
+ # loop via the usual SystemExit that gets sent when we die.
+ if self._interactive:
+ while (self._interpreter_start_time is None
+ or time.time() - self._interpreter_start_time < 0.5):
+ time.sleep(0.1)
+
+ # Avoid super fast death loops.
+ if (not self._subprocess_exited_cleanly and self._auto_restart
+ and not self._done):
+ time.sleep(5.0)
+
+ # If they don't want auto-restart, we'll exit the whole wrapper.
+ # (and with an error code if things ended badly).
+ if not self._auto_restart:
+ self._wrapper_shutdown_desired = True
+ if not self._subprocess_exited_cleanly:
+ self._should_report_subprocess_error = True
+
+ self._reset_subprocess_vars()
+
+ # If we want to die completely after this subprocess has ended,
+ # tell the main thread to die.
+ if self._wrapper_shutdown_desired:
+
+ # Only do this if the main thread is not already waiting for
+ # us to die; otherwise it can lead to deadlock.
+ # (we hang in os.kill while main thread is blocked in Thread.join)
+ if not self._done:
+ self._done = True
+
+ # This should break the main thread out of its blocking
+ # interpreter call.
+ os.kill(os.getpid(), signal.SIGTERM)
+
+ def _prep_subprocess_environment(self) -> None:
"""Write files that must exist at process launch."""
- os.makedirs('dist/ba_root', exist_ok=True)
- if os.path.exists('dist/ba_root/config.json'):
- with open('dist/ba_root/config.json') as infile:
+
+ assert self._ba_root_path is not None
+ os.makedirs(self._ba_root_path, exist_ok=True)
+ cfgpath = os.path.join(self._ba_root_path, 'config.json')
+ if os.path.exists(cfgpath):
+ with open(cfgpath) as infile:
bincfg = json.loads(infile.read())
else:
bincfg = {}
@@ -318,7 +648,8 @@ class ServerManagerApp:
bincfg['Port'] = self._config.port
bincfg['Auto Balance Teams'] = self._config.auto_balance_teams
bincfg['Show Tutorial'] = False
- with open('dist/ba_root/config.json', 'w') as outfile:
+ bincfg['Idle Exit Minutes'] = self._config.idle_exit_minutes
+ with open(cfgpath, 'w') as outfile:
outfile.write(json.dumps(bincfg))
def _enqueue_server_command(self, command: ServerCommand) -> None:
@@ -326,8 +657,8 @@ class ServerManagerApp:
Can be called from any thread.
"""
- with self._process_commands_lock:
- self._process_commands.append(command)
+ with self._subprocess_commands_lock:
+ self._subprocess_commands.append(command)
def _send_server_command(self, command: ServerCommand) -> None:
"""Send a command to the server.
@@ -335,19 +666,22 @@ class ServerManagerApp:
Must be called from the server process thread.
"""
import pickle
- assert current_thread() is self._process_thread
- assert self._process is not None
- assert self._process.stdin is not None
+ assert current_thread() is self._subprocess_thread
+ assert self._subprocess is not None
+ assert self._subprocess.stdin is not None
val = repr(pickle.dumps(command))
assert '\n' not in val
execcode = (f'import ba._servermode;'
f' ba._servermode._cmd({val})\n').encode()
- self._process.stdin.write(execcode)
- self._process.stdin.flush()
+ self._subprocess.stdin.write(execcode)
+ self._subprocess.stdin.flush()
- def _run_process_until_exit(self) -> None:
- assert self._process is not None
- assert self._process.stdin is not None
+ def _run_subprocess_until_exit(self) -> None:
+ if self._subprocess is None:
+ return
+
+ assert current_thread() is self._subprocess_thread
+ assert self._subprocess.stdin is not None
# Send the initial server config which should kick things off.
# (but make sure its values are still valid first)
@@ -361,76 +695,153 @@ class ServerManagerApp:
break
# Pass along any commands to our process.
- with self._process_commands_lock:
- for incmd in self._process_commands:
+ with self._subprocess_commands_lock:
+ for incmd in self._subprocess_commands:
# If we're passing a raw string to exec, no need to wrap it
# in any proper structure.
if isinstance(incmd, str):
- self._process.stdin.write((incmd + '\n').encode())
- self._process.stdin.flush()
+ self._subprocess.stdin.write((incmd + '\n').encode())
+ self._subprocess.stdin.flush()
else:
self._send_server_command(incmd)
- self._process_commands = []
+ self._subprocess_commands = []
- # Request a soft restart after a while.
- assert self._process_launch_time is not None
- sincelaunch = time.time() - self._process_launch_time
- if (self._restart_minutes is not None and sincelaunch >
- (self._restart_minutes * 60.0)
- and not self._process_sent_auto_restart):
- print(f'{Clr.CYN}restart_minutes ({self._restart_minutes})'
- f' elapsed; requesting child-process'
- f' soft restart...{Clr.RST}')
- self.restart()
- self._process_sent_auto_restart = True
+ # Request restarts/shut-downs for various reasons.
+ self._request_shutdowns_or_restarts()
- # Watch for the process exiting.
- code: Optional[int] = self._process.poll()
+ # If they want to force-kill our subprocess, simply exit this
+ # loop; the cleanup code will kill the process if its still
+ # alive.
+ if (self._subprocess_force_kill_time is not None
+ and time.time() > self._subprocess_force_kill_time):
+ print(
+ f'{Clr.CYN}Immediate shutdown time limit'
+ f' ({self.IMMEDIATE_SHUTDOWN_TIME_LIMIT:.1f} seconds)'
+ f' expired; force-killing subprocess...{Clr.RST}',
+ flush=True)
+ break
+
+ # Watch for the server process exiting..
+ code: Optional[int] = self._subprocess.poll()
if code is not None:
- if code == 0:
- clr = Clr.CYN
- slp = 0.0
- else:
- clr = Clr.SRED
- slp = 5.0 # Avoid super fast death loops.
- print(f'{clr}Server child-process exited'
- f' with code {code}.{Clr.RST}')
- self._reset_process_vars()
- time.sleep(slp)
+
+ clr = Clr.CYN if code == 0 else Clr.RED
+ print(
+ f'{clr}Server subprocess exited'
+ f' with code {code}.{Clr.RST}',
+ flush=True)
+ self._subprocess_exited_cleanly = (code == 0)
break
time.sleep(0.25)
- def _reset_process_vars(self) -> None:
- self._process = None
- self._process_launch_time = None
- self._process_sent_auto_restart = False
+ def _request_shutdowns_or_restarts(self) -> None:
+ # pylint: disable=too-many-branches
+ assert current_thread() is self._subprocess_thread
+ assert self._subprocess_launch_time is not None
+ now = time.time()
+ minutes_since_launch = (now - self._subprocess_launch_time) / 60.0
- def _kill_process(self) -> None:
- """End the server process if it still exists."""
- assert current_thread() is self._process_thread
- if self._process is None:
+ # If we're doing auto-restart with config changes, handle that.
+ if (self._auto_restart and self._config_auto_restart
+ and not self._subprocess_sent_config_auto_restart):
+ if (self._last_config_mtime_check_time is None
+ or (now - self._last_config_mtime_check_time) > 3.123):
+ self._last_config_mtime_check_time = now
+ mtime: Optional[float]
+ if os.path.isfile(self._config_path):
+ mtime = Path(self._config_path).stat().st_mtime
+ else:
+ mtime = None
+ if mtime != self._config_mtime:
+ print(
+ f'{Clr.CYN}Config-file change detected;'
+ f' requesting immediate restart.{Clr.RST}',
+ flush=True)
+ self.restart(immediate=True)
+ self._subprocess_sent_config_auto_restart = True
+
+ # Attempt clean exit if our clean-exit-time passes.
+ # (and enforce a 6 hour max if not provided)
+ clean_exit_minutes = 360.0
+ if self._config.clean_exit_minutes is not None:
+ clean_exit_minutes = min(clean_exit_minutes,
+ self._config.clean_exit_minutes)
+ if clean_exit_minutes is not None:
+ if (minutes_since_launch > clean_exit_minutes
+ and not self._subprocess_sent_clean_exit):
+ opname = 'restart' if self._auto_restart else 'shutdown'
+ print(
+ f'{Clr.CYN}clean_exit_minutes'
+ f' ({clean_exit_minutes})'
+ f' elapsed; requesting soft'
+ f' {opname}.{Clr.RST}',
+ flush=True)
+ if self._auto_restart:
+ self.restart(immediate=False)
+ else:
+ self.shutdown(immediate=False)
+ self._subprocess_sent_clean_exit = True
+
+ # Attempt unclean exit if our unclean-exit-time passes.
+ # (and enforce a 7 hour max if not provided)
+ unclean_exit_minutes = 420.0
+ if self._config.unclean_exit_minutes is not None:
+ unclean_exit_minutes = min(unclean_exit_minutes,
+ self._config.unclean_exit_minutes)
+ if unclean_exit_minutes is not None:
+ if (minutes_since_launch > unclean_exit_minutes
+ and not self._subprocess_sent_unclean_exit):
+ opname = 'restart' if self._auto_restart else 'shutdown'
+ print(
+ f'{Clr.CYN}unclean_exit_minutes'
+ f' ({unclean_exit_minutes})'
+ f' elapsed; requesting immediate'
+ f' {opname}.{Clr.RST}',
+ flush=True)
+ if self._auto_restart:
+ self.restart(immediate=True)
+ else:
+ self.shutdown(immediate=True)
+ self._subprocess_sent_unclean_exit = True
+
+ def _reset_subprocess_vars(self) -> None:
+ self._subprocess = None
+ self._subprocess_launch_time = None
+ self._subprocess_sent_config_auto_restart = False
+ self._subprocess_sent_clean_exit = False
+ self._subprocess_sent_unclean_exit = False
+ self._subprocess_force_kill_time = None
+ self._subprocess_exited_cleanly = None
+
+ def _kill_subprocess(self) -> None:
+ """End the server subprocess if it still exists."""
+ assert current_thread() is self._subprocess_thread
+ if self._subprocess is None:
return
- print(f'{Clr.CYN}Stopping server process...{Clr.RST}')
+ print(f'{Clr.CYN}Stopping subprocess...{Clr.RST}', flush=True)
# First, ask it nicely to die and give it a moment.
# If that doesn't work, bring down the hammer.
- self._process.terminate()
+ self._subprocess.terminate()
try:
- self._process.wait(timeout=10)
+ self._subprocess.wait(timeout=10)
+ self._subprocess_exited_cleanly = (
+ self._subprocess.returncode == 0)
except subprocess.TimeoutExpired:
- self._process.kill()
- self._reset_process_vars()
- print(f'{Clr.CYN}Server process stopped.{Clr.RST}')
+ self._subprocess_exited_cleanly = False
+ self._subprocess.kill()
+ print(f'{Clr.CYN}Subprocess stopped.{Clr.RST}', flush=True)
def main() -> None:
- """Run a BallisticaCore server manager in interactive mode."""
+ """Run the BallisticaCore server manager."""
try:
- ServerManagerApp().run_interactive()
+ ServerManagerApp().run()
except CleanError as exc:
# For clean errors, do a simple print and fail; no tracebacks/etc.
+ # Any others will bubble up and give us the usual mess.
exc.pretty_print()
sys.exit(1)
diff --git a/assets/src/server/config_template.yaml b/assets/src/server/config_template.yaml
index b0868242..80cecd16 100644
--- a/assets/src/server/config_template.yaml
+++ b/assets/src/server/config_template.yaml
@@ -1,7 +1,7 @@
# To configure your server, create a config.yaml file in the same directory
-# as the ballisticacore_server script. This template config file can be
+# as the ballisticacore_server script. The config_template.yaml file can be
# copied or renamed as a convenient starting point.
-# Uncomment any of these values to set them.
+# Uncomment any of these values to override defaults.
#__CONFIG_TEMPLATE_VALUES__
diff --git a/assets/src/server/launch_ballisticacore_server.bat b/assets/src/server/launch_ballisticacore_server.bat
index 134ebd52..547324d6 100644
--- a/assets/src/server/launch_ballisticacore_server.bat
+++ b/assets/src/server/launch_ballisticacore_server.bat
@@ -1,2 +1,3 @@
-:: All this does is run the ballisticacore_server script with the included python interpreter
+:: Simply run the ballisticacore_server.py script with the bundled
+:: Python interpreter.
dist\\python.exe ballisticacore_server.py
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.iml b/ballisticacore-cmake/.idea/BallisticaCore.iml
new file mode 100644
index 00000000..f08604bb
--- /dev/null
+++ b/ballisticacore-cmake/.idea/BallisticaCore.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..98cb16b6
--- /dev/null
+++ b/ballisticacore-cmake/.idea/dictionaries/ericf.xml
@@ -0,0 +1,1075 @@
+
+
+
+ NOMINMAX
+ aabb
+ abcdefghijklmnopqrstuvwxyz
+ abouttab
+ absval
+ accel
+ accountid
+ achs
+ acinstance
+ ack'ed
+ acked
+ acks
+ aclass
+ aclass's
+ activityplayer
+ addcall
+ addchars
+ addrs
+ adjoint
+ adminset
+ adreno
+ affx
+ affy
+ affz
+ aftx
+ afty
+ aftz
+ aint
+ airborn
+ alext
+ alibaba
+ allocs
+ alot
+ alphaimg
+ alphapixels
+ alsa
+ alsoft
+ anchorx
+ animcurve
+ aniso
+ ansiwrap
+ anyofallof
+ aosp
+ apientry
+ appconfig
+ appname
+ appnameupper
+ appstate
+ argsjoined
+ asci
+ assigninput
+ athome
+ attrobj
+ audiocache
+ automagically
+ autoselect
+ availmins
+ avel
+ avels
+ axismotion
+ backgrounded
+ backgrounding
+ backtraces
+ ballistica
+ ballisticacore
+ barebones
+ basetype
+ basicsize
+ basn
+ bastd
+ bbbb
+ bbbbb
+ bbbbbb
+ bbbbbbb
+ bcfn
+ bdea
+ 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
+ bstat
+ bsuuid
+ btnlabel
+ bucketnum
+ bufs
+ buildconfig
+ buildnumber
+ buttondown
+ buttonmouse
+ buttonup
+ buttonwidget
+ bwst
+ calced
+ calcing
+ calcs
+ caled
+ callargs
+ callbackobj
+ camalign
+ camelback
+ camerashake
+ cancelbtn
+ capitan
+ cargs
+ cbtnoffs
+ ccdd
+ ccontext
+ ccylinder
+ centiseconds
+ cfgdir
+ cfgpath
+ changeme
+ charn
+ charnum
+ charstr
+ chatmessage
+ chdir
+ checkboxwidget
+ checkchisel
+ chrono
+ chunksize
+ cjief
+ classdict
+ cleanupcheck
+ clientid
+ clientinfo
+ clipcount
+ 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
+ cresult
+ crom
+ crosswire
+ crvel
+ csize
+ cspr
+ cspre
+ csspbt
+ cstdint
+ cstdlib
+ cstring
+ ctargetref
+ cubemap
+ curtime
+ cutef
+ cvar
+ data
+ datadata
+ dataout
+ datas
+ datav
+ datavec
+ dbgstr
+ 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
+ dummyval
+ dummyvalid
+ dxgi
+ dynamicdata
+ echidna
+ edef
+ efro
+ efrohack
+ efrohome
+ elapsedf
+ elems
+ elevenbase
+ elevenbits
+ emitfx
+ emojis
+ enablexinput
+ endcall
+ endl
+ endline
+ endtime
+ entrypoint
+ enumvalue
+ enval
+ envcfg
+ envs
+ 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
+ fflush
+ fgets
+ fieldname
+ fieldpath
+ fifteenbits
+ filterstr
+ filterval
+ finishedptr
+ firstpartykey
+ fjco
+ fjcoiwef
+ flipbit
+ flopsy
+ fname
+ fnode
+ fnumc
+ focuswindow
+ fopen
+ fourcc
+ fovs
+ fovx
+ fovy
+ framebuffers
+ framedef
+ frameldefs
+ framerates
+ fread
+ freeform
+ freeifaddrs
+ freemins
+ freqs
+ froemling
+ fromini
+ 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
+ gethostbyname
+ getifaddrs
+ getinputdevice
+ getline
+ getlog
+ getmodel
+ getname
+ getnodes
+ getnodetype
+ getpackagecollidemodel
+ getpackagedata
+ getpackagemodel
+ getpackagesound
+ getpackagetexture
+ getpublicpartyenabled
+ getpublicpartymaxsize
+ getqrcodetexture
+ getres
+ getsession
+ getsound
+ gettexture
+ gettotalrefcount
+ gles
+ glext
+ googleplaytab
+ 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
+ hostingconfig
+ hostingstate
+ hotkeys
+ hotplug
+ hscrollwidget
+ htonf
+ htonl
+ htons
+ ibuf
+ icloud
+ iconscale
+ ieeefp
+ ifaddr
+ ifaddrs
+ ifdebug
+ iiiiisss
+ iircade
+ illum
+ ilock
+ imagewidget
+ incentivized
+ inet
+ inides
+ initguid
+ inittab
+ inputdevice
+ inputter
+ insta
+ intercollide
+ internalformat
+ interuptions
+ intstr
+ invote
+ iobj
+ iserverget
+ iserverput
+ isinst
+ isn'
+ isosplayingmusic
+ isutf
+ itemsize
+ itri
+ itsclass
+ itunes
+ ival
+ ivals
+ ized
+ jackmorgan
+ jacobian
+ janktastic
+ janky
+ jaxis
+ jcjwf
+ jmessage
+ keepalives
+ keycode
+ keyfilt
+ keysyms
+ keywds
+ khronos
+ kickable
+ kickee
+ killable
+ killcount
+ kmod
+ kronk
+ kwds
+ kxyz
+ lantinga
+ largeish
+ larmbeast
+ lasti
+ lastline
+ lastvalid
+ leaderboard
+ leaderboards
+ lenval
+ lgui
+ lhalf
+ libutf
+ lightshad
+ linearsize
+ linearstep
+ listobj
+ llock
+ lockpath
+ lockstr
+ locktype
+ logmsg
+ logpath
+ logprefix
+ logput
+ logsuffix
+ lorient
+ lowp
+ lpos
+ lpsockaddr
+ lrintf
+ lscope
+ lstr
+ lsync
+ ltypes
+ lvec
+ lvoid
+ macmusicappgetlibrarysource
+ macmusicappgetplaylists
+ macmusicappgetvolume
+ macmusicappinit
+ macmusicappplayplaylist
+ macmusicappsetvolume
+ macmusicappstop
+ macos
+ magoogan
+ magua
+ mainmenu
+ mallocs
+ manualtab
+ maskhigh
+ maskuv
+ maximus
+ maxtries
+ maxwidth
+ mediump
+ memalign
+ memchr
+ memcpy
+ meshdata
+ messagebox
+ meth
+ mhbegin
+ mhend
+ mikirog
+ millisecs
+ minelem
+ minsdl
+ mipmapcount
+ mipmaps
+ mmask
+ mmdevapi
+ modder
+ modelview
+ moduletype
+ momemtary
+ moreso
+ mqrspec
+ msaa
+ mult
+ multing
+ multipass
+ multisample
+ multitouch
+ multiway
+ musicplayerplay
+ musicplayersetvolume
+ musicplayershutdown
+ musicplayerstop
+ mutli
+ mybuf
+ mycallback
+ mynode
+ mystatspage
+ mywidget
+ nameval
+ ndebug
+ nearbytab
+ nearval
+ needwindow
+ negativex
+ negativey
+ negativez
+ nemanja
+ ness
+ netclient
+ netcode
+ netplay
+ nettest
+ newactivity
+ newchild
+ newimg
+ newitem
+ newname
+ newnode
+ nextchar
+ nitpicky
+ nlpos
+ nmemb
+ noassets
+ nodetype
+ nofilename
+ noglobs
+ nointhash
+ nominmax
+ noninfringement
+ noninteractive
+ noninteractively
+ nonlint
+ noone
+ nothin
+ nowtickets
+ nptr
+ nsize
+ ntoa
+ ntohl
+ numargs
+ numc
+ numentries
+ numlock
+ nval
+ nvidia
+ nyffenegger
+ objexists
+ objid
+ obstack
+ obvs
+ oculus
+ oenval
+ offsx
+ offsy
+ oiffsss
+ okbtn
+ 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
+ outpath
+ outputter
+ outval
+ outvalue
+ ouya
+ parameteriv
+ passcode
+ pausable
+ pdst
+ persp
+ pflag
+ pflags
+ pgmout
+ pixelformat
+ playpause
+ playsound
+ plen
+ pname
+ podcast
+ podcasts
+ portaudio
+ positivex
+ positivey
+ positivez
+ postinit
+ postrun
+ powerup
+ pptabcom
+ precalc
+ predeclare
+ prefs
+ preloaded
+ preloads
+ premult
+ prereq
+ prerun
+ printf
+ printnodes
+ printobjects
+ priv
+ privatetab
+ profilers
+ prog
+ proj
+ projdir
+ prolly
+ psmx
+ pspec
+ psps
+ psrc
+ pton
+ ptrs
+ ptype
+ publictab
+ 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
+ resetbtn
+ resetinput
+ resync
+ retrysecs
+ retval
+ rezing
+ rgui
+ richcompare
+ rigth
+ rootwidget
+ rowwidget
+ rresize
+ rresult
+ rscode
+ rsgc
+ runnables
+ rvec
+ rvel
+ safecolor
+ samsung
+ sapspace
+ savebtn
+ savebutton
+ scancode
+ scenetime
+ screenmessage
+ scrollwidget
+ sdkcheck
+ sdl's
+ sdlk
+ selchild
+ selindex
+ selwidget
+ selwidgets
+ seqlen
+ seqtype
+ seqtypestr
+ serv
+ serverget
+ servernodes
+ serverput
+ sessiondata
+ sessionglobals
+ sessionplayer
+ sessionteam
+ sessiontype
+ sessiontypestr
+ setactivity
+ setattro
+ setattrofunc
+ setdata
+ setname
+ setnode
+ setpublicpartyenabled
+ setpublicpartymaxsize
+ setpublicpartyname
+ setpublicpartystatsurl
+ setschedparam
+ setsockopt
+ sgis
+ sharedobj
+ shhh
+ shifthigh
+ shouldnt
+ shufflable
+ signsubscale
+ simd
+ simpletype
+ sisssssssss
+ sixteenbits
+ smoothering
+ smoothstep
+ smoothy
+ sndio
+ snorm
+ sockaddr
+ soffs
+ solaris
+ sourcenode
+ spacecount
+ spaz
+ spead
+ sphrand
+ spinup
+ spivak
+ srcattr
+ srcpath
+ srcsz
+ sresult
+ sscanf
+ ssize
+ sssi
+ sssisisis
+ sssissss
+ ssss
+ sssss
+ sssssi
+ sssssss
+ sssssssd
+ sssssssi
+ ssssssssssss
+ ssval
+ standin
+ startedptr
+ startpos
+ starttime
+ startx
+ starty
+ staticdata
+ stdint
+ stepfast
+ stephane
+ stepnum
+ stepsize
+ storecmd
+ strcasecmp
+ strchr
+ strcpy
+ strdup
+ stringi
+ strlen
+ strs
+ strtof
+ subargs
+ subclsssing
+ subentities
+ subfieldpath
+ subitems
+ subpaths
+ subplatform
+ subscale
+ subscr
+ subtypestr
+ sval
+ symbolification
+ syscalls
+ tabdefs
+ tabtype
+ tabtypes
+ talloc
+ tegra
+ telefonaktiebolaget
+ teleported
+ teleporting
+ tempvec
+ tenum
+ testint
+ testnode
+ texel
+ texqualstr
+ textcolor
+ textwidget
+ thang
+ thecommand
+ theres
+ threadname
+ threadtype
+ ticon
+ tiltage
+ timedisplay
+ timeformat
+ timerlist
+ timestep
+ timesteps
+ timetype
+ timetypes
+ tmpmat
+ tomer
+ topos
+ touchpad
+ toucs
+ toutf
+ tracebacks
+ tracestr
+ trackpad
+ trackpads
+ tradeoff
+ trailcolor
+ transobj
+ treturn
+ trifunovic
+ trilinear
+ trimesh
+ trimeshes
+ trynum
+ tself
+ tval
+ tvos
+ tweakage
+ twotimer
+ twst
+ typeobj
+ typestr
+ uber
+ uibounds
+ uiid
+ unblessed
+ uncas
+ unchecking
+ underrun
+ underruns
+ unformatted
+ unichar
+ unichars
+ uninited
+ unmanaged
+ unpaused
+ unplayed
+ unpremultiply
+ unsignaled
+ unstuff
+ unsynchronized
+ uppercased
+ userspace
+ uther
+ uuids
+ uxxxx
+ uxxxxxxxx
+ valign
+ valobj
+ vals
+ valtab
+ valuedispatchmethod
+ 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
+ wsroot
+ 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..bd40a33a
--- /dev/null
+++ b/ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..eb719c91
--- /dev/null
+++ b/ballisticacore-cmake/.idea/misc.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..bbbd75dc
--- /dev/null
+++ b/ballisticacore-cmake/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ballisticacore-cmake/.idea/scopes/External.xml b/ballisticacore-cmake/.idea/scopes/External.xml
new file mode 100644
index 00000000..a140a57c
--- /dev/null
+++ b/ballisticacore-cmake/.idea/scopes/External.xml
@@ -0,0 +1,3 @@
+
+
+
\ 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..a2e95531
--- /dev/null
+++ b/ballisticacore-cmake/CMakeLists.txt
@@ -0,0 +1,665 @@
+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 homebrew paths.
+ # Just hard-coding recommended homebrew install paths for now.
+ # Is there a more elegant way to do this?
+ if (CMAKE_SYSTEM_PROCESSOR MATCHES arm64)
+ list(APPEND CMAKE_PREFIX_PATH /opt/homebrew)
+ include_directories("/opt/homebrew/include")
+ link_directories("/opt/homebrew/lib")
+ else()
+ list(APPEND CMAKE_PREFIX_PATH /usr/local)
+ include_directories("/usr/local/include")
+ link_directories("/usr/local/lib")
+ endif()
+
+ # On Mac with homebrew it seems that Requesting 3.X when we've got
+ # 3.(X+1) installed will point us at the 3.(X+1) framework but will attempt
+ # to load a 3.X library from within it which doesn't exist. So we need
+ # to be a bit more explicit telling it where to look. Note: this was last
+ # tested with 3.7; should revisit sometime to make sure still applies.
+ 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)
+ if ("${SDL2_LIBRARIES}" STREQUAL "")
+ message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
+ set(SDL2_LIBRARIES "SDL2::SDL2")
+ endif ()
+ # 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_CXX_COMPILER_ID MATCHES GNU)
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -Wno-psabi")
+endif()
+
+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)
+else ()
+ # It seems that cmake can choose -O2 sometimes and -O3 sometimes
+ # for release builds (depending on Release vs RelWithDebInfo, etc).
+ # Let's keep all our non-debug builds consistent at -O3 for now; can
+ # revisit if it causes problems.
+ add_definitions(-O3)
+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})
+
+# NOTE: There used to be an issue with optimized GCC builds where mesh
+# collisions would fail randomly, leading to characters falling through
+# floors somewhat regularly. For this reason I was limiting optimization to
+# -O1 for the rigid body library. However, as of April 2021, all seems
+# well when testing on arm64 and x86-64 linux builds. (I think)
+# The last time I remember seeing this bug was around 2016 I believe, but I
+# haven't looked for it since. Perhaps GCC was fixed or perhaps the error
+# was limited to 32 bit x86 builds; in either case we should be good, as
+# we're no longer building any 32 bit x86 builds using GCC.
+# Keeping this in here commented out just in case it rears its ugly head
+# again though.
+# if (CMAKE_BUILD_TYPE MATCHES Release)
+# if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
+# target_compile_options(ode PRIVATE -O1)
+# endif()
+# endif ()
+
+# BallisticaCore binary.
+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.cc
+ ${BA_SRC_ROOT}/ballistica/app/app_config.h
+ ${BA_SRC_ROOT}/ballistica/app/app_globals.cc
+ ${BA_SRC_ROOT}/ballistica/app/app_globals.h
+ ${BA_SRC_ROOT}/ballistica/app/headless_app.cc
+ ${BA_SRC_ROOT}/ballistica/app/headless_app.h
+ ${BA_SRC_ROOT}/ballistica/app/stress_test.cc
+ ${BA_SRC_ROOT}/ballistica/app/stress_test.h
+ ${BA_SRC_ROOT}/ballistica/app/vr_app.cc
+ ${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_set.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.cc
+ ${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.cc
+ ${BA_SRC_ROOT}/ballistica/game/player.h
+ ${BA_SRC_ROOT}/ballistica/game/player_spec.cc
+ ${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.cc
+ ${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.cc
+ ${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
+ )
+
+target_include_directories(ballisticacore PRIVATE
+ ${Python_INCLUDE_DIRS}
+ ${BA_SRC_ROOT}/external/open_dynamics_engine-ef
+ ${EXTRA_INCLUDE_DIRS}
+ )
+
+target_link_libraries(ballisticacore PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}/prefablib/libballisticacore_internal.a ode pthread ${Python_LIBRARIES}
+ ${SDL2_LIBRARIES} ${EXTRA_LIBRARIES} dl)
+
+# Hack for building on rpi (might be due to my manually built Python 3.8)
+# Hopefully can remove later...
+if(EXISTS "/home/pi")
+target_link_libraries(ballisticacore PRIVATE dl util)
+endif()
diff --git a/config/config.json b/config/config.json
index db5e30f5..f5c5b98b 100644
--- a/config/config.json
+++ b/config/config.json
@@ -2,16 +2,37 @@
"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": [
+ "__main__",
"astroid.modutils",
"astroid",
"pylint.lint",
"pytest",
"pytz",
"yaml",
- "requests"
+ "requests",
+ "typing_extensions",
+ "cpplint",
+ "ansiwrap",
+ "filelock"
],
"python_paths": [
"assets/src/ba_data/python",
diff --git a/config/toolconfigsrc/editorconfig b/config/toolconfigsrc/editorconfig
index e87af068..8d9056d4 100644
--- a/config/toolconfigsrc/editorconfig
+++ b/config/toolconfigsrc/editorconfig
@@ -1,22 +1,35 @@
-# For configuring supported editors
+# Common config file for supported editors; see editorconfig.org.
+# If you are using an editor that doesn't support editorconfig, try to
+# conform to these settings manually.
-# This is the top-most EditorConfig file
+# Note: while we autogenerate this file, we also check it into git
+# because it affects how source is displayed on github.
+
+# This is the top-most EditorConfig file.
root = true
-# Defaults for all files
+# Defaults for all files.
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
-# Python overrides
+# Python overrides.
[*.py]
indent_style = space
indent_size = 4
max_line_length = 79
charset = utf-8
-# Makefile overrides
+# Makefile overrides.
[Makefile]
indent_style = tab
+indent_size = 2
max_line_length = 80
+
+# C/C++ overrides.
+[*.{c,cc,h,cpp,hpp}]
+indent_style = space
+indent_size = 2
+max_line_length = 80
+
diff --git a/config/toolconfigsrc/mypy.ini b/config/toolconfigsrc/mypy.ini
index 299b6668..86b64008 100644
--- a/config/toolconfigsrc/mypy.ini
+++ b/config/toolconfigsrc/mypy.ini
@@ -3,13 +3,37 @@ 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
+[mypy-cpplint.*]
+ignore_missing_imports = True
+
+[mypy-ansiwrap.*]
+ignore_missing_imports = True
+
[mypy-xml.*]
ignore_missing_imports = True
-[mypy-vis_cleanup]
+# We delete a bunch of stuff from _ba in here
+# which our public stub module doesn't list,
+# so we get complaints that they don't exist.
+[mypy-ba_embedded_vis_cleanup]
ignore_errors = True
[mypy-bastd.mapdata.*]
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/config/toolconfigsrc/pylintrc b/config/toolconfigsrc/pylintrc
index 8d17ef52..cbe6f4f0 100644
--- a/config/toolconfigsrc/pylintrc
+++ b/config/toolconfigsrc/pylintrc
@@ -62,25 +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 handful 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,
- T,
+ id,
S,
+ T,
U,
_
diff --git a/docs/ba_module.md b/docs/ba_module.md
index d69ae731..9c72a6ed 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 2021-04-17 for Ballistica version 1.6.0 build 20343
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,13 +20,21 @@
ba.NodeActor
ba.Chooser
+ ba.Collision
+ ba.GameResults
+ ba.GameTip
ba.InputDevice
ba.Level
ba.Lobby
ba.Material
ba.Node
ba.Player
+
+ ba.PlayerInfo
ba.PlayerRecord
+ ba.ScoreConfig
ba.Session
+ ba.SessionPlayer
+ ba.SessionTeam
+ ba.Setting
+ ba.StandLocation
ba.Stats
ba.Team
- ba.TeamGameResults
+
@@ -71,12 +85,17 @@
@@ -122,6 +142,7 @@
ba.OutOfBoundsMessage
ba.PickedUpMessage
ba.PickUpMessage
+ ba.PlayerDiedMessage
ba.PlayerScoredMessage
ba.PowerupAcceptMessage
ba.PowerupMessage
@@ -132,12 +153,21 @@
@@ -168,28 +198,50 @@
+
+
+
+
<top level class>
@@ -306,11 +358,48 @@ actually award achievements.
Create the banner/sound for an acquired achievement announcement.
+
+
+
+<top level class>
+
+Subsystem for achievement handling.
+
+Category: App Classes
+
+ Access the single shared instance of this class at 'ba.app.ach'.
+
+
+Methods:
+
+
+
+ba.AchievementSubsystem()
+
+
+
+achievements_for_coop_level(self, level_name: str) -> List[Achievement]
+
+Given a level name, return achievements available for it.
+
+
+
+award_local_achievement(self, achname: str) -> None
+
+For non-game-based achievements such as controller-connection.
+
+
+
+get_achievement(self, name: str) -> Achievement
+
+Return an Achievement by name.
+
inherits from: ba.DependencyComponent
+Inherits from: ba.DependencyComponent , typing.Generic
Units of execution wrangled by a ba.Session .
Category: Gameplay Classes
@@ -320,14 +409,42 @@ actually award achievements.
can overlap during transitions.
Attributes:
-
+
+
+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.
+
+
+
+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'.
+
+
+
+ba.Node
+The 'globals' ba.Node for the activity. This contains various
+ global controls and values.
+
+
-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.
+
+
+Type[PlayerType]
+The type of ba.Player this Activity is using.
+
ba.Session
@@ -336,9 +453,12 @@ join or leave the game.
Raises a ba.SessionNotFoundError if the Session no longer exists.
-
+
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.
@@ -349,26 +469,31 @@ join or leave the game.
-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).
+
+
+Type[TeamType]
+The type of ba.Team this Activity is using.
+
Methods Inherited:
Methods Defined or Overridden:
-
+
-ba.Activity(settings: Dict[str, Any])
+ba.Activity(settings: dict)
-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 ()
+
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.
@@ -385,10 +510,28 @@ are transitioned in.
(called by the ba.Actor base class)
-
-create_player_node(self, player: ba.Player ) -> ba.Node
+
+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(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.
@@ -425,16 +568,6 @@ will replace the old.
Return whether on_transition_in() has been called.
-
-
-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(self) -> bool
@@ -464,7 +597,7 @@ can begin.
-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.
@@ -472,13 +605,13 @@ can begin.
-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(self, team: ba.Team ) -> None
+on_team_join(self, team: TeamType) -> None
Called when a new ba.Team joins the Activity.
@@ -486,7 +619,7 @@ can begin.
-on_team_leave(self, team: ba.Team ) -> None
+on_team_leave(self, team: TeamType) -> None
Called when a ba.Team leaves the Activity.
@@ -497,8 +630,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.
@@ -507,7 +640,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.
@@ -520,11 +653,17 @@ called.
returns False for the Actor. The ba.Actor.autoretain () method
is a convenient way to access this same functionality.
+
+
+transition_out(self) -> None
+
+Called by the Session to start us transitioning out.
+
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
@@ -543,7 +682,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
@@ -582,6 +722,7 @@ is a convenient way to access this same functionality.
Attributes:
+
ba.Activity
@@ -589,10 +730,17 @@ is a convenient way to access this same functionality.
Raises a ba.ActivityNotFoundError if the Activity no longer exists.
+
+
+bool
+Whether the Actor is expired.
+
+ (see ba.Actor.on_expire ())
+
Methods:
-
+
ba.Actor()
@@ -640,7 +788,7 @@ even if myactor is set to None.
Return the ba.Activity this Actor is associated with.
If the Activity no longer exists, raises a ba.ActivityNotFoundError
-or returns None depending on whether 'doraise' is set.
+or returns None depending on whether 'doraise' is True.
@@ -659,26 +807,18 @@ It is not a requirement for Actors to be
able to die; just that they report whether
they are Alive or not.
-
-
-is_expired(self) -> bool
-
-Returns whether the Actor is expired.
-
-(see ba.Actor.on_expire ())
-
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
+
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.
@@ -687,7 +827,7 @@ likely result in errors.
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
@@ -710,17 +850,17 @@ likely result in errors.
Attributes:
-
+
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.
@@ -749,39 +889,10 @@ likely result in errors.
builds due to compiler optimizations being disabled and extra
checks being run.
-
-
-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.
-
-
-
-str
-The name of the language the game is running in.
-
- This can be selected explicitly by the user or may be set
- automatically based on ba.App.locale or other factors.
-
-
-
-str
-Raw country/language code detected by the game (such as 'en_US').
-
- Generally for language-specific code you should look at
- ba.App.language , which is the language the game is using
- (which may differ from locale if the user sets a language, etc.)
-
bool
-Bool value for if the game is running on a TV.
+Whether the game is currently running on a TV.
@@ -791,12 +902,12 @@ likely result in errors.
Examples are: 'mac', 'windows', android'.
-
+
str
Path where the app looks for its bundled scripts.
-
+
str
Path containing pip packages bundled with the app.
@@ -845,7 +956,7 @@ likely result in errors.
bool
-Bool value for if the game is running in VR.
+Whether the game is currently running in VR.
@@ -861,7 +972,7 @@ likely result in errors.
launch_coop_game(self, 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.
@@ -895,7 +1006,7 @@ to resume.
-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.
@@ -903,7 +1014,7 @@ to resume.
inherits from: dict
+Inherits from: builtins.dict
A special dict that holds the game's persistent configuration values.
Category: App Classes
@@ -916,7 +1027,7 @@ to resume.
AppConfig data is stored as json on disk on so make sure to only place
json-friendly values in it (dict, list, str, float, int, bool).
- Be aware that tuples will be quietly converted to lists.
+ Be aware that tuples will be quietly converted to lists when stored.
Methods Defined or Overridden:
@@ -1005,8 +1116,8 @@ manually.
Methods:
-
-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(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.
@@ -1017,7 +1128,7 @@ when done.
inherits from: ba.DependencyComponent
+Inherits from: ba.DependencyComponent
ba.DependencyComponent representing a bundled package of game assets.
Category: Asset Classes
@@ -1080,6 +1191,21 @@ when done.
Behavior is similar to ba.gettexture ()
+
+
+
+Inherits from: ba.Setting
+A boolean game setting.
+
+Category: Settings Classes
+
+
+Methods:
+
+
+ba.BoolSetting(name: str, default: bool)
+
@@ -1104,8 +1230,10 @@ when done.
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)
@@ -1126,8 +1254,18 @@ mycall()
Attributes:
-
+
+
+Dict[str, Any]
+Return the live config dict for this campaign.
+
+
+
+List[ba.Level ]
+The list of ba.Levels in the Campaign.
+
+
str
The name of the Campaign.
@@ -1140,41 +1278,29 @@ mycall()
Methods:
-
+
ba.Campaign(name: str, sequential: bool = True)
-
-add_level(self, level: ba.Level ) -> None
+
+addlevel(self, level: ba.Level ) -> None
Adds a ba.Level to the Campaign.
-
-
-get_config_dict(self) -> Dict[str, Any]
-
-Return the live config dict for this campaign.
-
-
-
-get_level(self, name: str) -> ba.Level
-
-Return a contained ba.Level by name.
-
-
-
-get_levels(self) -> List[ba.Level ]
-
-Return the set of ba.Levels in the Campaign.
-
get_selected_level(self) -> str
Return the name of the Level currently selected in the UI.
+
+
+getlevel(self, name: str) -> ba.Level
+
+Return a contained ba.Level by name.
+
reset(self) -> None
@@ -1210,6 +1336,21 @@ mycall()
ba.CelebrateMessage(duration: float = 10.0)
+
+
+
+Inherits from: ba.Setting
+A setting with multiple choices.
+
+Category: Settings Classes
+
+
+Methods:
+
+
+ba.ChoiceSetting(name: str, default: Any, choices: List[Tuple[str, Any]])
+
@@ -1222,29 +1363,34 @@ mycall()
Attributes:
-
+
ba.Lobby
The chooser's ba.Lobby .
-
-
-ba.Player
-The ba.Player associated with this chooser.
-
bool
Whether this chooser is checked in as ready.
+
+
+ba.SessionPlayer
+The ba.SessionPlayer associated with this chooser.
+
+
+
+ba.SessionTeam
+Return this chooser's currently selected ba.SessionTeam .
+
Methods:
-
+
-ba.Chooser(vpos: float, player: _ba.Player , lobby: "Lobby")
+ba.Chooser(vpos: float, sessionplayer: _ba.SessionPlayer , lobby: "Lobby")
@@ -1270,15 +1416,9 @@ mycall()
Return this chooser's lobby if it still exists; otherwise None.
-
-
-get_team(self) -> ba.Team
-
-Return this chooser's selected ba.Team .
-
-getplayer(self) -> ba.Player
+getplayer(self) -> ba.SessionPlayer
Return the player associated with this chooser.
@@ -1295,10 +1435,10 @@ mycall()
Reload all player profiles.
-
-update_from_player_profiles(self) -> None
+
+update_from_profile(self) -> None
-Set character based on profile; otherwise use pre-picked random.
+Set character/colors based on the current profile.
@@ -1318,6 +1458,47 @@ mycall()
Use ba.getcollidemodel () to instantiate one.
+
+<top level class>
+
+A class providing info about occurring collisions.
+
+Category: Gameplay Classes
+
+
+Attributes:
+
+
+
+int
+The body index on the opposing node in the current collision.
+
+
+
+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.
+
+
+
+ba.Vec3
+The position of the current collision.
+
+
+
+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).
+
+
+
<top level class>
@@ -1354,11 +1535,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.
@@ -1405,37 +1586,78 @@ 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.
start_long_action(callback_when_done=ba.ContextCall (self.mycallback))
+
+Inherits from: Exception , BaseException
+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.
+
+
+Methods:
+<all methods inherited from Exception >
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
Attributes Inherited:
-
+
Attributes Defined Here:
-
+
+
+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.
+
+
+
+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'.
+
+
+
+ba.Node
+The 'globals' ba.Node for the activity. This contains various
+ global controls and values.
+
+
ba.Map
The map being used for this game.
Raises a ba.NotFoundError if the map does not currently exist.
+
+
+Type[PlayerType]
+The type of ba.Player this Activity is using.
+
ba.Session
@@ -1450,15 +1672,20 @@ start_long_action(callback_when_done=ba.ContextC
If access is attempted before or after, raises a ba.NotFoundError .
+
+
+Type[TeamType]
+The type of ba.Team this Activity is using.
+
Methods Inherited:
-
+
Methods Defined or Overridden:
-ba.CoopGameActivity(settings: Dict[str, Any])
+ba.CoopGameActivity(settings: dict)
Instantiate the Activity.
@@ -1501,7 +1728,7 @@ and it should begin its actual game logic.
-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.
@@ -1516,20 +1743,34 @@ and it should begin its actual game logic.
inherits from: ba.Session
+Inherits from: ba.Session
A ba.Session which runs cooperative-mode games.
Category: Gameplay Classes
These generally consist of 1-4 players against
the computer and include functionality such as
- high score lists.
-
+ high score lists.
Attributes Inherited:
-
+
+Attributes Defined Here:
+
+
+
+Optional[ba.Campaign ]
+The ba.Campaign instance this Session represents, or None if
+there is no associated Campaign.
+
+
+
+ba.Node
+The sessionglobals ba.Node for the session.
+
+
+
Methods Inherited:
-
+
Methods Defined or Overridden:
@@ -1565,9 +1806,9 @@ is pressed.
-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.
@@ -1604,7 +1845,7 @@ the data object is requested and when it's value is accessed.
inherits from: enum.Enum
+Inherits from: enum.Enum
A reason for a death.
Category: Enums
@@ -1620,8 +1861,18 @@ the data object is requested and when it's value is accessed.
LEFT_GAME
+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 >
+
inherits from: typing.Generic
+Inherits from: typing.Generic
A dependency on a DependencyComponent (with an optional config).
Category: Dependency Classes
@@ -1694,7 +1945,7 @@ on the dep config value. (for instance a map required by a game type)
inherits from: Exception, BaseException
+Inherits from: Exception , BaseException
Exception raised when one or more ba.Dependency items are missing.
Category: Exception Classes
@@ -1721,7 +1972,7 @@ on the dep config value. (for instance a map required by a game type)
inherits from: typing.Generic
+Inherits from: typing.Generic
Set of resolved dependencies and their associated data.
Category: Dependency Classes
@@ -1853,16 +2104,24 @@ its time with lingering corpses, sound effects, etc.
inherits from: ba.MultiTeamSession , ba.Session
+Inherits from: ba.MultiTeamSession , ba.Session
ba.Session type for teams mode games.
Category: Gameplay Classes
Attributes Inherited:
-
+
+Attributes Defined Here:
+
+
+ba.Node
+The sessionglobals ba.Node for the session.
+
+
+
Methods Inherited:
-
+
Methods Defined or Overridden:
@@ -1870,20 +2129,180 @@ its time with lingering corpses, sound effects, etc.
Set up playlists and launches a ba.Activity to accept joiners.
+
+
+
+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 those top level
+ classes 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 should do so
+ for both.
+
+
+Attributes Inherited:
+
+Attributes Defined Here:
+
+
+
+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.
+
+
+
+ba.Node
+A ba.Node of type 'player' associated with this Player.
+
+ This node can be used to get a generic player position/etc.
+
+
+
+ba.Vec3
+The position of the player, as defined by its current ba.Actor .
+
+ If the player currently has no actor, raises a ba.ActorNotFoundError .
+
+
+
+ba.SessionPlayer
+Return the ba.SessionPlayer corresponding to this Player.
+
+ Throws a ba.SessionPlayerNotFoundError if it does not exist.
+
+
+
+TeamType
+The ba.Team for this player.
+
+
+
+Methods:
+<all methods inherited from ba.Player >
+
+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 those top level
+ classes 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 should do so
+ for both.
+
+
+Attributes:
+
+
+
+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
+Return the ba.SessionTeam corresponding to this Team.
+
+ Throws a ba.SessionTeamNotFoundError if there is none.
+
+
+
+Methods:
+<all methods inherited from ba.Team >
+
+Inherits from: typing.Protocol , typing.Generic
+A Protocol for objects supporting an exists() method.
+
+Category: Protocols
+
+
+Methods:
+
+
+exists(self) -> bool
+
+Whether this object exists.
+
+
+
+
+Inherits from: ba.ChoiceSetting , ba.Setting
+A float setting with multiple choices.
+
+Category: Settings Classes
+
+
+Methods:
+
+
+ba.FloatChoiceSetting(name: str, default: float, choices: List[Tuple[str, float]])
+
+
+
+
+Inherits from: ba.Setting
+A floating point game setting.
+
+Category: Settings Classes
+
+
+Methods:
+
+
+ba.FloatSetting(name: str, default: float, min_value: float = 0.0, max_value: float = 9999.0, increment: float = 1.0)
+
inherits from: ba.MultiTeamSession , ba.Session
+Inherits from: ba.MultiTeamSession , ba.Session
ba.Session type for free-for-all mode games.
Category: Gameplay Classes
Attributes Inherited:
-
+
+Attributes Defined Here:
+
+
+ba.Node
+The sessionglobals ba.Node for the session.
+
+
+
Methods Inherited:
-
+
Methods Defined or Overridden:
@@ -1922,23 +2341,51 @@ its time with lingering corpses, sound effects, etc.
inherits from: ba.Activity , ba.DependencyComponent
-Common base class for all game ba.Activities.
+Inherits from: ba.Activity , ba.DependencyComponent , typing.Generic
+Common base class for all game ba.Activities .
Category: Gameplay Classes
Attributes Inherited:
-
+
Attributes Defined Here:
-
+
+
+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.
+
+
+
+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'.
+
+
+
+ba.Node
+The 'globals' ba.Node for the activity. This contains various
+ global controls and values.
+
+
ba.Map
The map being used for this game.
Raises a ba.NotFoundError if the map does not currently exist.
+
+
+Type[PlayerType]
+The type of ba.Player this Activity is using.
+
ba.Session
@@ -1953,15 +2400,20 @@ its time with lingering corpses, sound effects, etc.
If access is attempted before or after, raises a ba.NotFoundError .
+
+
+Type[TeamType]
+The type of ba.Team this Activity is using.
+
Methods Inherited:
-
+
Methods Defined or Overridden:
-
+
-ba.GameActivity(settings: Dict[str, Any])
+ba.GameActivity(settings: dict)
Instantiate the Activity.
@@ -1973,24 +2425,24 @@ its time with lingering corpses, sound effects, etc.
and calls either end_game or continue_game depending on the result
-
+
<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(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 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_settings () and ba.GameActivity.get_supported_maps ()
-they can just rely on the default implementation here which calls those
-methods.
+ba.GameActivity.get_available_settings () and
+ba.GameActivity.get_supported_maps () they can just rely on
+the default implementation here which calls those methods.
@@ -2007,31 +2459,31 @@ will replace the old.
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.
-
+
<class method>
-get_config_display_string(config: Dict[str, Any]) -> ba.Lstr
+get_available_settings(sessiontype: Type[ba.Session ]) -> List[ba.Setting ]
-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.
+Return a list of settings relevant to this game type when
+running under the provided session type.
<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.
@@ -2049,7 +2501,7 @@ activity type (in English) within the context of the given
Return a descriptive name for this game/settings combo.
-Subclasses should override get_name(); not this.
+Subclasses should override getname(); not this.
@@ -2060,7 +2512,7 @@ activity type (in English) within the context of the given
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;
@@ -2068,25 +2520,19 @@ 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
+# 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['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
the first value, ${ARG2} with the second, etc.
-
-get_instance_display_string(self) -> ba.Lstr
-
-Return a name for this particular game instance.
-
-
-
-get_instance_scoreboard_description(self) -> Union[str, Sequence]
+
+get_instance_description_short(self) -> Union[str, Sequence]
Return a short description for this game instance in English.
@@ -2101,16 +2547,22 @@ 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
+# 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['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 the first value, ${ARG2} with the second, etc.
+
+
+get_instance_display_string(self) -> ba.Lstr
+
+Return a name for this particular game instance.
+
get_instance_scoreboard_display_string(self) -> ba.Lstr
@@ -2121,112 +2573,21 @@ with the first value, ${ARG2} with the second, etc.
of the screen, so it should be as concise as possible.
-
+
<class method>
-get_name() -> str
+get_settings_display_string(config: Dict[str, Any]) -> ba.Lstr
-Return a str name for this game type.
+Given a game config dict, return a short description for it.
-
-
-<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.
-
-
-
-<class method>
-get_score_info() -> 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.
-
-
-
-<class method>
-get_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
-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_settings() implementation for a capture-the-flag game:
-@classmethod
-def get_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
- })]
+This is used when viewing game-lists or showing what game
+is up next in a series.
<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.
@@ -2237,6 +2598,22 @@ for this game-type for the given ba.Session type
Given a team name, returns a localized version of it.
+
+
+<class method>
+getname() -> str
+
+Return a str name for this game type.
+
+This default implementation simply returns the 'name' class attr.
+
+
+
+<class method>
+getscoreconfig() -> ba.ScoreConfig
+
+Return info about game scoring setup; can be overridden by games.
+
handlemessage(self, msg: Any) -> Any
@@ -2269,18 +2646,12 @@ whatever is relevant to keep the game going.
-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.
(including the initial set of Players)
-
-
-on_player_leave(self, player: ba.Player ) -> None
-
-Called when a ba.Player is leaving the Activity.
-
on_transition_in(self) -> None
@@ -2288,22 +2659,13 @@ 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.
-
-
-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(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.
@@ -2327,21 +2689,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(self) -> None
-
-Show the game description.
-
-
-
-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(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
@@ -2350,7 +2697,7 @@ and short description of the game.
-spawn_player(self, player: ba.Player ) -> ba.Actor
+spawn_player(self, player: PlayerType) -> ba.Actor
Spawn *something* for the provided ba.Player .
@@ -2358,7 +2705,7 @@ and short description of the game.
-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.
@@ -2367,7 +2714,7 @@ and short description of the game.
-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 .
@@ -2378,6 +2725,116 @@ and short description of the game.
Return whether this game supports the provided Session type.
+
+
+
+<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:
+
+
+
+bool
+Whether lower scores are better.
+
+
+
+List[ba.PlayerInfo ]
+Get info about the players represented by the results.
+
+
+
+str
+The label associated with scores ('points', etc).
+
+
+
+ba.ScoreType
+The type of score.
+
+
+
+List[ba.SessionTeam ]
+Return all ba.SessionTeams in the results.
+
+
+
+List[WinnerGroup]
+Get an ordered list of winner groups.
+
+
+
+Optional[ba.SessionTeam ]
+The winning ba.SessionTeam if there is exactly one, or else None.
+
+
+
+Methods:
+
+
+
+ba.GameResults()
+
+
+
+get_sessionteam_score(self, sessionteam: ba.SessionTeam ) -> Optional[int]
+
+Return the score for a given ba.SessionTeam .
+
+
+
+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.)
+
+
+
+has_score_for_sessionteam(self, sessionteam: ba.SessionTeam ) -> bool
+
+Return whether there is a score for a given session-team.
+
+
+
+set_game(self, game: ba.GameActivity ) -> None
+
+Set the game instance these results are applying to.
+
+
+
+set_team_score(self, team: ba.Team , score: Optional[int]) -> None
+
+Set the score for a given team.
+
+This can be a number or None.
+(see the none_is_winner arg in the constructor)
+
+
+
+
+<top level class>
+
+Defines a tip presentable to the user at the start of a game.
+
+Category: Gameplay Classes
+
+
+Methods:
+
+
+ba.GameTip(text: str, icon: Optional[ba.Texture ] = None, sound: Optional[ba.Sound ] = None)
+
@@ -2393,12 +2850,19 @@ and short description of the game.
Methods:
+
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(self, playertype: Type[PlayerType]) -> Optional[PlayerType]
+
+Return the source-player if one exists and is the provided type.
+
@@ -2433,7 +2897,7 @@ and short description of the game.
Category: Gameplay Classes
Attributes:
-
+
bool
@@ -2447,9 +2911,11 @@ This is only meaningful for remote client inputs; for
all local devices this will be -1.
-
+
bool
-Whether the underlying device for this object is still present.
+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.)
@@ -2480,7 +2946,7 @@ client.
- Optional[ba.Player ]
+ Optional[ba.SessionPlayer ]
The player associated with this input device.
@@ -2493,8 +2959,14 @@ prefs, etc.
Methods:
-
+
+
+exists() -> bool
+
+Return whether the underlying device for this object is still present.
+
+
get_account_name(full: bool) -> str
@@ -2506,19 +2978,23 @@ prefs, etc.
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(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.
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
@@ -2527,6 +3003,188 @@ prefs, etc.
Methods:
<all methods inherited from ba.NotFoundError >
+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
+
+
+Inherits from: ba.ChoiceSetting , ba.Setting
+An int setting with multiple choices.
+
+Category: Settings Classes
+
+
+Methods:
+
+
+ba.IntChoiceSetting(name: str, default: int, choices: List[Tuple[str, int]])
+
+
+
+
+Inherits from: ba.Setting
+An integer game setting.
+
+Category: Settings Classes
+
+
+Methods:
+
+
+ba.IntSetting(name: str, default: int, min_value: int = 0, max_value: int = 9999, increment: int = 1)
+
+
+
+
+<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:
+
+
+
+List[Tuple[str, ...]]
+Used for row/column lengths.
+
+
+
+str
+Displays when user selecting this keyboard.
+
+
+
+Tuple[str, ...]
+The 'num' page.
+
+
+
+Dict[str, Tuple[str, ...]]
+Extra chars like emojis.
+
+
+
+
+<top level class>
+
+Wraps up language related app functionality.
+
+Category: App Classes
+
+ To use this class, access the single instance of it at 'ba.app.lang'.
+
+
+Attributes:
+
+
+
+List[str]
+A list of all available languages.
+
+ Note that languages that may be present in game assets but which
+ are not displayable on the running version of the game are not
+ included here.
+
+
+
+str
+The name of the language the game is running in.
+
+ This can be selected explicitly by the user or may be set
+ automatically based on ba.App .locale or other factors.
+
+
+
+str
+Raw country/language code detected by the game (such as 'en_US').
+
+ Generally for language-specific code you should look at
+ ba.App .language, which is the language the game is using
+ (which may differ from locale if the user sets a language, etc.)
+
+
+
+Methods:
+
+
+
+ba.LanguageSubsystem()
+
+
+
+get_resource(self, resource: str, fallback_resource: str = None, fallback_value: Any = None) -> Any
+
+Return a translation resource by name.
+
+DEPRECATED; use ba.Lstr functionality for these purposes.
+
+
+
+is_custom_unicode_char(self, char: str) -> bool
+
+Return whether a char is in the custom unicode range we use.
+
+
+
+setlanguage(self, language: Optional[str], print_change: bool = True, store_to_config: bool = True) -> None
+
+Set the active language used for the game.
+
+Pass None to use OS default language.
+
+
+
+translate(self, category: str, strval: str, raise_exceptions: bool = False, print_errors: bool = False) -> str
+
+Translate a value (or return the value if no translation available)
+
+DEPRECATED; use ba.Lstr functionality for these purposes.
+
+
+
+
<top level class>
@@ -2536,8 +3194,13 @@ prefs, etc.
Attributes:
-
+
+
+Optional[ba.Campaign ]
+The ba.Campaign this Level is associated with, or None.
+
+
bool
Whether this Level has been completed.
@@ -2578,22 +3241,14 @@ prefs, etc.
Methods:
-
+
-ba.Level(name: str, gametype: Type[ba.GameActivity ], settings: Dict[str, Any], preview_texture_name: str, displayname: str = None)
-
-Initializes a Level object with the provided values.
-
-
-
-get_campaign(self) -> Optional[ba.Campaign ]
-
-Return the ba.Campaign this Level is associated with, or None.
+ba.Level(name: str, gametype: Type[ba.GameActivity ], settings: dict, preview_texture_name: str, displayname: str = None)
-get_high_scores(self) -> Dict
+get_high_scores(self) -> dict
Return the current high scores for this Level.
@@ -2648,11 +3303,11 @@ can be changed to separate its new high score lists/etc. from the old.
Attributes:
-
+
-
-List[ba.Team ]
-Teams available in this lobby.
+
+List[ba.SessionTeam ]
+ba.SessionTeams available in this lobby.
@@ -2671,7 +3326,7 @@ can be changed to separate its new high score lists/etc. from the old.
-add_chooser(self, player: ba.Player ) -> None
+add_chooser(self, sessionplayer: ba.SessionPlayer ) -> None
Add a chooser to the lobby for the provided player.
@@ -2718,9 +3373,9 @@ Intended for use in initial joining-screens.
-remove_chooser(self, player: ba.Player ) -> None
+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.
@@ -2769,7 +3424,7 @@ needs a chooser.
Methods:
-
+
ba.Lstr(*args: Any, **keywds: Any)
@@ -2796,6 +3451,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(json_string: str) -> ba.Lstr
+
+Given a json string, returns a ba.Lstr . Does no data validation.
+
is_flat_value(self) -> bool
@@ -2811,7 +3472,7 @@ etc.
inherits from: ba.Actor
+Inherits from: ba.Actor
A game map.
Category: Gameplay Classes
@@ -2821,6 +3482,7 @@ etc.
Attributes:
+
ba.Activity
@@ -2828,12 +3490,19 @@ etc.
Raises a ba.ActivityNotFoundError if the Activity no longer exists.
+
+
+bool
+Whether the Actor is expired.
+
+ (see ba.Actor.on_expire ())
+
Methods Inherited:
-
+
Methods Defined or Overridden:
-
+
ba.Map(vr_overlay_offset: Optional[Sequence[float]] = None)
@@ -2908,13 +3577,6 @@ as far from these players as possible.
If None is returned, default music will be used.
-
-
-<class method>
-get_name() -> str
-
-Return the unique name of this map, in English.
-
<class method>
@@ -2935,6 +3597,13 @@ as far from these players as possible.
Return a random starting position for the given team index.
+
+
+<class method>
+getname() -> str
+
+Return the unique name of this map, in English.
+
handlemessage(self, msg: Any) -> Any
@@ -3140,10 +3809,67 @@ 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)))
+
+
+
+<top level class>
+
+Subsystem for working with script metadata in the app.
+
+Category: App Classes
+
+ Access the single shared instance of this class at 'ba.app.meta'.
+
+
+Methods:
+
+
+
+ba.MetadataSubsystem()
+
+
+
+get_game_types(self) -> List[Type[ba.GameActivity ]]
+
+Return available game types.
+
+
+
+get_scan_results(self) -> ScanResults
+
+Return meta scan results; block if the scan is not yet complete.
+
+
+
+get_unowned_game_types(self) -> Set[Type[ba.GameActivity ]]
+
+Return present game types not owned by the current account.
+
+
+
+handle_scan_results(self, results: ScanResults) -> None
+
+Called in the game thread with results of a completed scan.
+
+
+
+on_app_launch(self) -> None
+
+Should be called when the app is done bootstrapping.
+
+
+
+start_scan(self) -> None
+
+Begin scanning script directories for scripts containing metadata.
+
+Should be called only once at launch.
+
@@ -3159,7 +3885,7 @@ Use ba.getmodel () to instantiate one.
inherits from: ba.Session
+Inherits from: ba.Session
Common base class for ba.DualTeamSession and ba.FreeForAllSession .
Category: Gameplay Classes
@@ -3169,9 +3895,17 @@ Use ba.getmodel () to instantiate one.
Attributes Inherited:
-
+
+Attributes Defined Here:
+
+
+ba.Node
+The sessionglobals ba.Node for the session.
+
+
+
Methods Inherited:
-
+
Methods Defined or Overridden:
@@ -3182,7 +3916,7 @@ Use ba.getmodel () to instantiate one.
-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.
@@ -3232,7 +3966,7 @@ another ba.Activity .
-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.
@@ -3323,7 +4057,7 @@ signify that the default soundtrack should be used..
inherits from: enum.Enum
+Inherits from: enum.Enum
Influences behavior when playing music.
Category: Enums
@@ -3335,8 +4069,98 @@ signify that the default soundtrack should be used..
TEST
+<top level class>
+
+Subsystem for music playback in the app.
+
+Category: App Classes
+
+ Access the single shared instance of this class at 'ba.app.music'.
+
+
+Methods:
+
+
+
+ba.MusicSubsystem()
+
+
+
+do_play_music(self, musictype: Union[MusicType, str, None], continuous: bool = False, mode: MusicPlayMode = <MusicPlayMode.REGULAR: regular>, testsoundtrack: Dict[str, Any] = None) -> None
+
+Plays the requested music type/mode.
+
+For most cases, setmusic() is the proper call to use, which itself
+calls this. Certain cases, however, such as soundtrack testing, may
+require calling this directly.
+
+
+
+get_music_player(self) -> MusicPlayer
+
+Returns the system music player, instantiating if necessary.
+
+
+
+get_soundtrack_entry_name(self, entry: Any) -> str
+
+Given a soundtrack entry, returns its name.
+
+
+
+get_soundtrack_entry_type(self, entry: Any) -> str
+
+Given a soundtrack entry, returns its type, taking into
+account what is supported locally.
+
+
+
+have_music_player(self) -> bool
+
+Returns whether a music player is present.
+
+
+
+music_volume_changed(self, val: float) -> None
+
+Should be called when changing the music volume.
+
+
+
+on_app_launch(self) -> None
+
+Should be called by app on_app_launch().
+
+
+
+on_app_resume(self) -> None
+
+Should be run when the app resumes from a suspended state.
+
+
+
+on_app_shutdown(self) -> None
+
+Should be called when the app is shutting down.
+
+
+
+set_music_play_mode(self, mode: MusicPlayMode, force_restart: bool = False) -> None
+
+Sets music play mode; used for soundtrack testing/etc.
+
+
+
+supports_soundtrack_entry_type(self, entry_type: str) -> bool
+
+Return whether provided soundtrack entry type is supported here.
+
+
+
+
inherits from: enum.Enum
+Inherits from: enum.Enum
Types of music available to play in-game.
Category: Enums
@@ -3394,7 +4218,7 @@ a live node in the game.
Node reference (sometimes used as attr values/etc).
Methods:
-
+
add_death_action(action: Callable[[], None]) -> None
@@ -3422,8 +4246,8 @@ loc.connectattr('position', light, 'position')
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.
@@ -3438,17 +4262,20 @@ functionality, so a statement such as "if mynode" will do
the right thing both for Node objects and values of None.
-
-get_name() -> str
+
+getdelegate(type: Type, doraise: bool = False) -> <varies>
-Return the name assigned to a Node; used mainly for debugging
+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
+ba.DelegateNotFoundError will be raised instead.
-
-getdelegate() -> Any
+
+getname() -> str
-Returns the node's current delegate, which is the Python object
-designated to handle the Node's messages.
+Return the name assigned to a Node; used mainly for debugging
@@ -3478,7 +4305,7 @@ acting as an alternative to setting node attributes.
inherits from: ba.Actor
+Inherits from: ba.Actor
A simple ba.Actor type that wraps a single ba.Node .
Category: Gameplay Classes
@@ -3488,6 +4315,7 @@ acting as an alternative to setting node attributes.
Attributes:
+
ba.Activity
@@ -3495,10 +4323,17 @@ acting as an alternative to setting node attributes.
Raises a ba.ActivityNotFoundError if the Activity no longer exists.
+
+
+bool
+Whether the Actor is expired.
+
+ (see ba.Actor.on_expire ())
+
Methods Inherited:
-
+
Methods Defined or Overridden:
@@ -3537,7 +4372,7 @@ even if myactor is set to None.
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
@@ -3547,14 +4382,14 @@ even if myactor is set to None.
<all methods inherited from ba.NotFoundError >
inherits from: Exception, BaseException
+Inherits from: Exception , BaseException
Exception raised when a referenced object does not exist.
Category: Exception Classes
Methods:
-<all methods inherited from builtins.Exception >
+<all methods inherited from Exception >
<top level class>
@@ -3573,7 +4408,7 @@ even if myactor is set to None.
inherits from: enum.Enum
+Inherits from: enum.Enum
Permissions that can be requested from the OS.
Category: Enums
@@ -3631,185 +4466,202 @@ even if myactor is set to None.
<top level class>
-
-A reference to a player in the game.
+Inherits from: typing.Generic
+A player in a specific ba.Activity .
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.
+ 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:
-
+
- Optional[ba.Actor ]
-The current ba.Actor associated with this Player.
-This may be None
+Optional[ba.Actor ]
+The ba.Actor associated with the player.
-
- str
-The character this player has selected in their profile.
-
-
-
- Sequence[float]
-The base color for this Player.
-In team games this will match the ba.Team 's color.
-
-
-
- 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.
-
-
-
- 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 .
-
-
-
- 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.
-
-
-
- bool
-This bool value will be True once the Player has completed
-any lobby character/team selection.
+
+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.
- 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.
-
- 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.
+
+ba.Vec3
+The position of the player, as defined by its current ba.Actor .
+
+ If the player currently has no actor, raises a ba.ActorNotFoundError .
+
+
+
+ba.SessionPlayer
+Return the ba.SessionPlayer corresponding to this Player.
+
+ Throws a ba.SessionPlayerNotFoundError if it does not exist.
- 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.
+TeamType
+The ba.Team for this player.
Methods:
-
+
-
-assign_input_call(type: Union[str, Tuple[str, ...]],
- call: Callable) -> None
+
+assigninput(self, inputtype: 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'
+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.
-
-get_account_id() -> str
+
+exists(self) -> bool
-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).
+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.
-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() -> int
+
+getname(self, full: bool = False, icon: bool = True) -> str
-Returns the unique numeric player ID for this player.
-
-
-
-get_input_device() -> ba.InputDevice
-
-Returns the player's input device.
-
-
-
-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.
-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() -> None
+
+on_expire(self) -> None
-Removes the player from the game.
+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.
-
-reset_input() -> None
+
+resetinput(self) -> None
+
+resetinput() -> None
Clears out the player's assigned input actions.
-
-set_actor(actor: Optional[ba.Actor ]) -> None
+
+
+<top level class>
+
+A message saying a ba.Player has died.
-Set the player's associated ba.Actor .
+Category: Message Classes
+
+Attributes:
+
+
+
+ba.DeathType
+The particular type of death.
-
-set_name(name: str, full_name: str = None, real: bool = True)
- -> None
+
+bool
+If True, the player was killed;
+If False, they left the game or the round ended.
-Set the player's name to the provided string.
-A number will automatically be appended if the name is not unique from
-other players.
+
+
+Methods:
+
+
+
+ba.PlayerDiedMessage(player: ba.Player , was_killed: bool, killerplayer: Optional[ba.Player ], how: ba.DeathType )
+
+Instantiate a message with the given values.
+
+
+
+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(self, playertype: Type[PlayerType]) -> PlayerType
+
+Return the ba.Player that died.
+
+The type of player for the current activity should be passed so that
+the type-checker properly identifies the returned value as one.
+
+
+
+
+<top level class>
+
+Holds basic info about a player.
+
+Category: Gameplay Classes
+
+
+Methods:
+
+
+ba.PlayerInfo(name: str, character: str)
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
@@ -3834,32 +4686,33 @@ other players.
-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.
-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.
Methods:
-
+
-ba.PlayerRecord(name: str, name_full: str, player: ba.Player , stats: ba.Stats )
+ba.PlayerRecord(name: str, name_full: str, sessionplayer: ba.SessionPlayer , stats: ba.Stats )
-
-associate_with_player(self, player: ba.Player ) -> None
+
+associate_with_sessionplayer(self, sessionplayer: ba.SessionPlayer ) -> None
-Associate this entry with a ba.Player .
+Associate this entry with a ba.SessionPlayer .
@@ -3874,17 +4727,11 @@ other players.
Get the icon for this instance's player.
-
-get_last_player(self) -> ba.Player
+
+get_last_sessionplayer(self) -> ba.SessionPlayer
Return the last ba.Player we were associated with.
-
-
-get_name(self, full: bool = False) -> str
-
-Return the player entry's name.
-
getactivity(self) -> Optional[ba.Activity ]
@@ -3893,6 +4740,12 @@ other players.
Returns None if the activity no longer exists.
+
+
+getname(self, full: bool = False) -> str
+
+Return the player entry's name.
+
submit_kill(self, showpoints: bool = True) -> None
@@ -3922,6 +4775,75 @@ other players.
ba.PlayerScoredMessage(score: int)
+
+
+
+<top level class>
+
+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.
+
+
+Methods:
+
+
+on_app_launch(self) -> None
+
+Called when the app is being launched.
+
+
+
+
+<top level class>
+
+Subsystem for plugin handling in the app.
+
+Category: App Classes
+
+ Access the single shared instance of this class at 'ba.app.plugins'.
+
+
+Methods:
+
+
+
+ba.PluginSubsystem()
+
+
+
+on_app_launch(self) -> None
+
+Should be called at app launch time.
+
+
+
+
+<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:
+
+
+ba.PotentialPlugin(display_name: ba.Lstr , class_path: str, available: bool)
+
@@ -3954,7 +4876,7 @@ other players.
This message is normally received by touching a ba.PowerupBox.
Attributes:
-
+
str
@@ -3962,11 +4884,11 @@ other players.
See ba.Powerup.poweruptype for available type values.
-
+
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.
@@ -3974,11 +4896,71 @@ cause the powerup box to make a sound and disappear or whatnot.
Methods:
-ba.PowerupMessage(poweruptype: str, source_node: Optional[ba.Node ] = None)
+ba.PowerupMessage(poweruptype: str, sourcenode: Optional[ba.Node ] = None)
+<top level class>
+
+Settings for how a game handles scores.
+
+Category: Gameplay Classes
+
+Attributes:
+
+
+
+str
+A label show to the user for scores; 'Score', 'Time Survived', etc.
+
+
+
+bool
+Whether lower scores are preferable. Higher scores are by default.
+
+
+
+bool
+Whether a value of None is considered better than other scores.
+By default it is not.
+
+
+
+ba.ScoreType
+How the score value should be displayed.
+
+
+
+str
+To change high-score lists used by a game without renaming the game,
+change this. Defaults to an empty string.
+
+
+
+Methods:
+
+
+ba.ScoreConfig(label: 'str' = 'Score', scoretype: 'ba.ScoreType ' = <ScoreType.POINTS: 'p'>, lower_is_better: 'bool' = False, none_is_winner: 'bool' = False, version: 'str' = '')
+
+
+
+
+Inherits from: enum.Enum
+Type of scores.
+
+Category: Enums
+
+
+Values:
+
+SECONDS
+MILLISECONDS
+POINTS
+
+
<top level class>
@@ -4032,7 +5014,7 @@ Pass 0 or a negative number for no ban time.
<top level class>
-Defines a high level series of activities with a common purpose.
+Defines a high level series of ba.Activities with a common purpose.
Category: Gameplay Classes
@@ -4044,12 +5026,18 @@ Pass 0 or a negative number for no ban time.
maintaining state between them (players, teams, score tallies, etc).
Attributes:
-
+
-
-Optional[ba.Campaign ]
-The ba.Campaign instance this Session represents, or None if
-there is no associated Campaign.
+
+bool
+Whether players should be allowed to join in the middle of
+activities.
+
+
+
+dict
+A shared dictionary for objects to use as storage on this session.
+Ensure that keys here are unique to avoid collisions.
@@ -4062,34 +5050,54 @@ any such selection.
int
-The maximum number of Players allowed in the Session.
+The maximum number of players allowed in the Session.
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.
-
-List[ba.Player ]
-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.
+
+ba.Node
+The sessionglobals ba.Node for the session.
-
-List[ba.Team ]
-All the ba.Teams in the Session. Most things should use the team
-list in ba.Activity ; not this.
+
+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.
+
+
+
+List[ba.SessionTeam ]
+All the ba.SessionTeams in the Session. Most things should use the
+list of ba.Teams in ba.Activity ; not this.
+
+
+
+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.
+
+
+
+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:
-
+
-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.
@@ -4158,13 +5166,13 @@ another ba.Activity .
-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(self, player: ba.Player ) -> bool
+on_player_request(self, player: ba.SessionPlayer ) -> bool
Called when a new ba.Player wants to join the Session.
@@ -4172,32 +5180,32 @@ another ba.Activity .
-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(self, team: ba.Team ) -> None
+on_team_leave(self, team: ba.SessionTeam ) -> None
Called when a ba.Team is leaving the session.
-
-set_activity(self, activity: ba.Activity ) -> None
+
+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)
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
@@ -4206,6 +5214,232 @@ session.set_activity(foo) and then ba.newnode
Methods:
<all methods inherited from ba.NotFoundError >
+<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 () method (or boolean operator) to ensure
+that a SessionPlayer is still present if retaining references to one
+for any length of time.
+
+Attributes:
+
+
+
+ Optional[ba.Player ]
+The current game-specific instance for this player.
+
+
+
+ str
+The character this player has selected in their profile.
+
+
+
+ Sequence[float]
+The base color for this Player.
+In team games this will match the ba.SessionTeam 's color.
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+ bool
+This bool value will be True once the Player has completed
+any lobby character/team selection.
+
+
+
+ ba.InputDevice
+The input device associated with the player.
+
+
+
+ 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:
+
+
+
+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.
+
+
+
+exists() -> bool
+
+Return whether the underlying player is still in the game.
+
+
+
+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() -> Dict[str, Any]
+
+Returns the character's icon (images, colors, etc contained in a dict)
+
+
+
+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.
+
+
+
+remove_from_game() -> None
+
+Removes the player from the game.
+
+
+
+resetinput() -> None
+
+Clears out the player's assigned input actions.
+
+
+
+setname(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.
+
+
+
+
+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 >
+
+<top level class>
+
+A team of one or more ba.SessionPlayers .
+
+Category: Gameplay Classes
+
+ Note that a SessionPlayer *always* has a SessionTeam;
+ in some cases, such as free-for-all ba.Sessions ,
+ each SessionTeam consists of just one SessionPlayer.
+
+Attributes:
+
+
+
+Tuple[float, ...]
+The team's color.
+
+
+
+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.
+
+
+
+int
+The unique numeric id of the team.
+
+
+
+Union[ba.Lstr , str]
+The team's name.
+
+
+
+List[ba.SessionPlayer ]
+The list of ba.SessionPlayers on the team.
+
+
+
+Methods:
+
+
+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.
+
+
+
+
+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 >
+
+<top level class>
+
+Defines a user-controllable setting for a game or other entity.
+
+Category: Gameplay Classes
+
+
+Methods:
+
+
+ba.Setting(name: str, default: Any)
+
+
+
+
<top level class>
@@ -4233,7 +5467,7 @@ session.set_activity(foo) and then ba.newnode
inherits from: enum.Enum
+Inherits from: enum.Enum
Special characters the game can print.
Category: Enums
@@ -4333,6 +5567,22 @@ session.set_activity(foo) and then ba.newnode
MIKIROG
+<top level class>
+
+Describes a point in space and an angle to face.
+
+Category: Gameplay Classes
+
+
+Methods:
+
+
+ba.StandLocation(position: ba.Vec3 , angle: Optional[float] = None)
+
+
+
+
<top level class>
@@ -4373,7 +5623,7 @@ session.set_activity(foo) and then ba.newnode
Methods:
-
+
ba.Stats()
@@ -4392,12 +5642,6 @@ session.set_activity(foo) and then ba.newnode
May return None.
-
-
-player_got_hit(self, player: ba.Player ) -> None
-
-Call this when a player got hit.
-
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
@@ -4413,10 +5657,10 @@ session.set_activity(foo) and then ba.newnode
Should be called when a player is killed.
-
-register_player(self, player: ba.Player ) -> None
+
+register_sessionplayer(self, player: ba.SessionPlayer ) -> None
-Register a player with this score-set.
+Register a ba.SessionPlayer with this score-set.
@@ -4431,8 +5675,8 @@ session.set_activity(foo) and then ba.newnode
Reset per-sound sub-scores.
-
-set_activity(self, activity: Optional[ba.Activity ]) -> None
+
+setactivity(self, activity: Optional[ba.Activity ]) -> None
Set the current activity for this instance.
@@ -4440,72 +5684,56 @@ session.set_activity(foo) and then ba.newnode
<top level class>
-
-A team of one or more ba.Players .
+Inherits from: typing.Generic
+A team in a specific ba.Activity .
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 .
+ These correspond to ba.SessionTeam objects, but are created per activity
+ so that the activity can use its own custom team subclass.
+
Attributes:
-
+
-
-Tuple[float, ...]
-The team's color.
+
+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.
-
-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 .
+
+SessionTeam
+Return the ba.SessionTeam corresponding to this Team.
-
-
-Union[ba.Lstr , str]
-The team's name.
-
-
-
-List[ba.Player ]
-The list of ba.Players on the team.
-
-
-
-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.
+ Throws a ba.SessionTeamNotFoundError if there is none.
Methods:
-
+
-
-ba.Team(team_id: 'int' = 0, name: 'Union[ba.Lstr , str]' = '', color: 'Sequence[float]' = (1.0, 1.0, 1.0))
+
+manual_init(self, team_id: int, name: Union[ba.Lstr , str], color: Tuple[float, ...]) -> None
-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.
+Manually init a team for uses such as bots.
-
-get_id(self) -> int
+
+on_expire(self) -> None
-Returns the numeric team ID.
+Can be overridden to handle team expiration.
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
@@ -4515,16 +5743,44 @@ of the session.
Attributes Inherited:
-
+
Attributes Defined Here:
-
+
+
+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.
+
+
+
+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'.
+
+
+
+ba.Node
+The 'globals' ba.Node for the activity. This contains various
+ global controls and values.
+
+
ba.Map
The map being used for this game.
Raises a ba.NotFoundError if the map does not currently exist.
+
+
+Type[PlayerType]
+The type of ba.Player this Activity is using.
+
ba.Session
@@ -4539,15 +5795,20 @@ of the session.
If access is attempted before or after, raises a ba.NotFoundError .
+
+
+Type[TeamType]
+The type of ba.Team this Activity is using.
+
Methods Inherited:
-
+
Methods Defined or Overridden:
-ba.TeamGameActivity(settings: Dict[str, Any])
+ba.TeamGameActivity(settings: dict)
Instantiate the Activity.
@@ -4575,13 +5836,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(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 .
@@ -4598,110 +5859,11 @@ on the ba.Player and their ba.DualTeamSessions and ba.FreeForAllSessions ;
False otherwise.
-
-
-
-<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.
-
-Methods:
-
-
-
-ba.TeamGameResults()
-
-Instantiate a results instance.
-
-
-
-get_lower_is_better(self) -> bool
-
-Return whether lower scores are better.
-
-
-
-get_player_info(self) -> List[Dict[str, Any]]
-
-Get info about the players represented by the results.
-
-
-
-get_score_name(self) -> str
-
-Get the name associated with scores ('points', etc).
-
-
-
-get_score_type(self) -> str
-
-Get the type of score.
-
-
-
-get_team_score(self, team: ba.Team ) -> Optional[int]
-
-Return the score for a given team.
-
-
-
-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.)
-
-
-
-get_teams(self) -> List[ba.Team ]
-
-Return all ba.Teams in the results.
-
-
-
-get_winners(self) -> List[WinnerGroup]
-
-Get an ordered list of winner groups.
-
-
-
-get_winning_team(self) -> Optional[ba.Team ]
-
-Get the winning ba.Team if there is exactly one; None otherwise.
-
-
-
-has_score_for_team(self, team: ba.Team ) -> bool
-
-Return whether there is a score for a given team.
-
-
-
-set_game(self, game: ba.GameActivity ) -> None
-
-Set the game instance these results are applying to.
-
-
-
-set_team_score(self, team: 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)
-
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
@@ -4737,7 +5899,7 @@ Results for a completed ba.TeamGameActivity
inherits from: enum.Enum
+Inherits from: enum.Enum
Specifies the format time values are provided in.
Category: Enums
@@ -4769,7 +5931,7 @@ you should use the ba.timer () function instead.
time: length of time (in seconds by default) that the timer will wait
before firing. Note that the actual delay experienced may vary
- depending on the timetype. (see below)
+depending on the timetype. (see below)
call: A callable Python object. Note that the timer will retain a
strong reference to the callable for as long as it exists, so you
@@ -4779,28 +5941,11 @@ desired.
repeat: if True, the timer will fire repeatedly, with each successive
firing having the same delay as the first.
-timetype can be either 'sim', 'base', or 'real'. It defaults to
-'sim'. Types are explained below:
+timetype: A ba.TimeType value determining which timeline the timer is
+placed onto.
-'sim' time maps to local simulation time in ba.Activity or ba.Session
-Contexts. This means that it may progress slower in slow-motion play
-modes, stop when the game is paused, etc. This time type is not
-available in UI contexts.
-
-'base' time is also linked to gameplay in ba.Activity or ba.Session
-Contexts, but it progresses at a constant rate regardless of
- slow-motion states or pausing. It can, however, slow down or stop
-in certain cases such as network outages or game slowdowns due to
-cpu load. Like 'sim' time, this is unavailable in UI contexts.
-
-'real' time always maps to actual clock time with a bit of filtering
-added, regardless of Context. (the filtering prevents it from going
-backwards or jumping forward by large amounts due to the app being
-backgrounded, system time changing, etc.)
-Real time timers are currently only available in the UI context.
-
-the 'timeformat' arg defaults to SECONDS but can also be MILLISECONDS
-if you want to pass time as milliseconds.
+timeformat: A ba.TimeFormat value determining how the passed time is
+interpreted.
# Example: use a Timer object to print repeatedly for a few seconds:
def say_it():
@@ -4808,14 +5953,14 @@ def say_it():
def stop_saying_it():
self.t = None
ba.screenmessage ('MUSHROOM MUSHROOM!')
-# create our timer; it will run as long as we hold self.t
+# Create our timer; it will run as long as we have the self.t ref.
self.t = ba.Timer (0.3, say_it, repeat=True)
-# now fire off a one-shot timer to kill it
+# Now fire off a one-shot timer to kill it.
ba.timer (3.89, stop_saying_it)
inherits from: enum.Enum
+Inherits from: enum.Enum
Specifies the type of time for various operations to target/use.
Category: Enums
@@ -4843,7 +5988,7 @@ self.t = ba.Timer (0.3, say_it, repeat=True)
<top level class>
-Wrangles UILocations.
+Wrangles ba.UILocations.
Category: User Interface Classes
@@ -4860,6 +6005,98 @@ self.t = ba.Timer (0.3, say_it, repeat=True)
Show the main menu, clearing other UIs from location stacks.
+
+
+
+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:
+
+
+<top level class>
+
+Consolidated UI functionality for the app.
+
+Category: App Classes
+
+ To use this class, access the single instance of it at 'ba.app.ui'.
+
+
+Attributes:
+
+
+ba.UIScale
+Current ui scale for the app.
+
+
+
+Methods:
+
+
+
+ba.UISubsystem()
+
+
+
+clear_main_menu_window(self, transition: str = None) -> None
+
+Clear any existing 'main' window with the provided transition.
+
+
+
+get_main_menu_location(self) -> Optional[str]
+
+Return the current named main menu location, if any.
+
+
+
+has_main_menu_window(self) -> bool
+
+Return whether a main menu window is present.
+
+
+
+on_app_launch(self) -> None
+
+Should be run on app launch.
+
+
+
+set_main_menu_location(self, location: str) -> None
+
+Set the location represented by the current main menu window.
+
+
+
+set_main_menu_window(self, window: ba.Widget ) -> None
+
+Set the current 'main' window, replacing any existing.
+
@@ -4964,8 +6201,10 @@ self.t = ba.Timer (0.3, say_it, repeat=True)
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:
@@ -5054,7 +6293,7 @@ widgets.
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
@@ -5075,7 +6314,7 @@ widgets.
-ba.Window(root_widget: ba.Widget )
+ba.Window(root_widget: ba.Widget , cleanupcheck: bool = True)
@@ -5221,6 +6460,50 @@ them elsewhere will be meaningless.
a new one is created and returned. Arguments that are not set to None
are applied to the Widget.
+
+clipboard_get_text() -> str
+
+Return text currently on the system clipboard.
+
+Category: General Utility Functions
+
+Ensure that ba.clipboard_has_text () returns True before calling
+ this function.
+
+
+clipboard_has_text() -> bool
+
+Return whether there is currently text on the clipboard.
+
+Category: General Utility Functions
+
+This will return False if no system clipboard is available; no need
+ to call ba.clipboard_available() separately.
+
+
+clipboard_is_supported() -> bool
+
+Return whether this platform supports clipboard operations at all.
+
+Category: General Utility Functions
+
+If this returns False, UIs should not show 'copy to clipboard'
+buttons, etc.
+
+
+clipboard_set_text(value: str) -> None
+
+Copy a string to the system clipboard.
+
+Category: General Utility Functions
+
+Ensure that ba.clipboard_available() returns True before adding
+ buttons/etc. that make use of this functionality.
+
columnwidget(edit: ba.Widget = None,
@@ -5234,7 +6517,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.
@@ -5260,7 +6548,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,
@@ -5290,7 +6578,7 @@ are applied to the Widget.
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
@@ -5322,41 +6610,60 @@ Note that the actual amount emitted may vary depending on graphics
settings, exiting element counts, or other factors.
-get_collision_info(*args: Any) -> Any
+existing(obj: Optional[ExistableType]) -> Optional[ExistableType]
-Return collision related values
+Convert invalid references to None for any ba.Existable object.
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
+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 (Optional[FooType]) into functions expecting only live ones
+(FooType), 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://ballistica.net/wiki/Coding-Style-Guide
-get_valid_languages() -> List[str]
+garbage_collect() -> None
-Return a list containing names of all available languages.
+Run an explicit pass of garbage collection.
Category: General Utility Functions
-Languages that may be present but are not displayable on the running
-version of the game are ignored.
+May also print warnings/etc. if collection takes too long or if
+uncollectible objects are found (so use this instead of simply
+gc.collect().
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.
+
+
+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()
@@ -5374,6 +6681,14 @@ 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.
+
+getcollision() -> Collision
+
+Return the in-progress collision.
+
+Category: Gameplay Functions
+
getmaps(playtype: str) -> List[str]
@@ -5444,7 +6759,7 @@ Category: Gameplay Functions
getsession(doraise: bool = True) -> ba.Session
+getsession(doraise: bool = True) -> <varies>
Category: Gameplay Functions
@@ -5489,7 +6804,10 @@ 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_up_down: bool = None,
+ claims_tab: bool = None) -> ba.Widget
Create or edit a horizontal scroll widget.
@@ -5545,8 +6863,8 @@ is only useful for simple URLs.)
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
@@ -5561,8 +6879,8 @@ issues unless to_server is False.
so in most cases you can just use that.
-new_activity(activity_type: Type[ba.Activity ],
+newactivity(activity_type: Type[ba.Activity ],
settings: dict = None) -> ba.Activity
Instantiates a ba.Activity given a type object.
@@ -5570,11 +6888,11 @@ 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.
newnode(type: str, owner: Union[Node, ba.Actor ] = None,
+newnode(type: str, owner: ba.Node = None,
attrs: dict = None, name: str = None, delegate: Any = None)
-> Node
@@ -5674,7 +6992,8 @@ It prints various info about the current object count, etc.
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.
@@ -5703,11 +7022,14 @@ app running.
rowwidget(edit: Widget =None, parent: Widget =None,
+rowwidget(edit: ba.Widget = None, parent: ba.Widget = None,
size: Sequence[float] = None,
position: Sequence[float] = None,
- background: bool = None, selected_child: Widget = None,
- visible_child: Widget = None) -> Widget
+ background: bool = None, selected_child: ba.Widget = None,
+ visible_child: ba.Widget = None,
+ claims_left_right: bool = None,
+ claims_tab: bool = None,
+ selection_loops_to_parent: bool = None) -> ba.Widget
Create or edit a row widget.
@@ -5758,7 +7080,12 @@ 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_up_down: bool = None,
+ claims_tab: bool = None,
+ autoselect: bool = None) -> ba.Widget
Create or edit a scroll widget.
@@ -5780,21 +7107,11 @@ are applied to the Widget.
'screen' should be a string description of an app location
('Main Menu', etc.)
-
-setlanguage(language: Optional[str], print_change: bool = True, store_to_config: bool = True) -> None
-
-Set the active language used for the game.
-
-Category: General Utility Functions
-
-Pass None to use OS default language.
-
setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None
+setmusic(musictype: Optional[ba.MusicType ], continuous: bool = False) -> None
-Tell the game to play (or stop playing) a certain type of music.
+Set the app to play (or stop playing) a certain type of music.
Category: Gameplay Functions
@@ -5807,54 +7124,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.
-
-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.
-
show_damage_count(damage: str, position: Sequence[float], direction: Sequence[float]) -> None
@@ -5863,18 +7132,44 @@ playing, the playing track will not be restarted.
Category: Gameplay Functions
+
+storagename(suffix: str = None) -> str
+
+Generate a unique name for storing class data in shared places.
+
+Category: General Utility Functions
+
+This consists of a leading underscore, the module path at the
+call site with dots replaced by underscores, the containing class's
+qualified name, and the provided suffix. When storing data in public
+places such as 'customdata' dicts, this minimizes the chance of
+collisions with other similarly named classes.
+
+Note that this will function even if called in the class definition.
+
+# Example: generate a unique name for storage purposes:
+class MyThingie:
+
+ # This will give something like '_mymodule_submodule_mythingie_data'.
+ _STORENAME = ba.storagename ('data')
+
+ # Use that name to store some data in the Activity we were passed.
+ def __init__(self, activity):
+ activity.customdata[self._STORENAME] = {}
+
textwidget(edit: Widget = None, parent: Widget = None,
+textwidget(edit: ba.Widget = None, parent: ba.Widget = None,
size: Sequence[float] = None, position: Sequence[float] = None,
text: Union[str, ba.Lstr ] = None, v_align: str = None,
h_align: str = None, editable: bool = None, padding: float = None,
on_return_press_call: Callable[[], None] = None,
on_activate_call: Callable[[], None] = None,
- selectable: bool = None, query: Widget = None, max_chars: int = None,
+ selectable: bool = None, query: ba.Widget = None, max_chars: int = None,
color: Sequence[float] = None, click_activate: bool = None,
on_select_call: Callable[[], None] = None,
- always_highlight: bool = None, draw_controller: Widget = None,
+ always_highlight: bool = None, draw_controller: ba.Widget = None,
scale: float = None, corner_scale: float = None,
description: Union[str, ba.Lstr ] = None,
transition_delay: float = None, maxwidth: float = None,
@@ -5897,7 +7192,7 @@ are applied to the Widget.
time(timetype: ba.TimeType = TimeType.SIM,
timeformat: ba.TimeFormat = TimeFormat.SECONDS)
- -> Union[float, int]
+ -> <varies>
Return the current time.
@@ -6037,6 +7332,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.
+
+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.
+
widget(edit: ba.Widget = None, up_widget: ba.Widget = None,
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.
diff --git a/src/ballistica/app/app.cc b/src/ballistica/app/app.cc
new file mode 100644
index 00000000..6bd078a5
--- /dev/null
+++ b/src/ballistica/app/app.cc
@@ -0,0 +1,398 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/app/app.h"
+
+#include "ballistica/app/stress_test.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), stress_test_(std::make_unique()) {
+ 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::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(InMainThread());
+ 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() {
+ // there's probably a better place for this...
+ stress_test_->Update();
+
+ // 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_) {
+ OnResume();
+ actually_paused_ = false;
+ }
+ } else {
+ // Pause if anyone wants.
+ if (sys_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([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([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(
+ [purchase, order_id] { g_platform->PurchaseAck(purchase, order_id); });
+}
+
+void App::PushGetScoresToBeatCall(const std::string& level,
+ const std::string& config,
+ void* py_callback) {
+ PushCall([level, config, py_callback] {
+ assert(InMainThread());
+ g_platform->GetScoresToBeat(level, config, py_callback);
+ });
+}
+
+void App::PushPurchaseCall(const std::string& item) {
+ PushCall([item] {
+ assert(InMainThread());
+ g_platform->Purchase(item);
+ });
+}
+
+void App::PushRestorePurchasesCall() {
+ PushCall([] {
+ assert(InMainThread());
+ g_platform->RestorePurchases();
+ });
+}
+
+void App::PushOpenURLCall(const std::string& url) {
+ PushCall([url] { g_platform->OpenURL(url); });
+}
+
+void App::PushGetFriendScoresCall(const std::string& game,
+ const std::string& game_version, void* data) {
+ PushCall([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([game, game_version, score] {
+ g_platform->SubmitScore(game, game_version, score);
+ });
+}
+
+void App::PushAchievementReportCall(const std::string& achievement) {
+ PushCall([achievement] { g_platform->ReportAchievement(achievement); });
+}
+
+void App::PushStringEditCall(const std::string& name, const std::string& value,
+ int max_chars) {
+ PushCall([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] {
+ stress_test_->SetStressTesting(enable, player_count);
+ });
+}
+
+void App::PushResetAchievementsCall() {
+ PushCall([] { 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([vis] {
+ assert(InMainThread());
+ g_platform->SetHardwareCursorVisible(vis);
+ });
+}
+
+} // namespace ballistica
diff --git a/src/ballistica/app/app.h b/src/ballistica/app/app.h
new file mode 100644
index 00000000..30576afc
--- /dev/null
+++ b/src/ballistica/app/app.h
@@ -0,0 +1,146 @@
+// Released under the MIT License. See LICENSE for details.
+
+#ifndef BALLISTICA_APP_APP_H_
+#define BALLISTICA_APP_APP_H_
+
+#include
+#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.
+ auto PostInit() -> void;
+
+ /// 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 auto PrimeEventPump() -> void;
+
+ /// 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 auto RunEvents() -> void;
+
+ // 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.
+ auto PauseApp() -> void;
+
+ 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.
+ auto ResumeApp() -> void;
+
+ /// 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.
+ auto SetScreenResolution(float width, float height) -> void;
+
+ /// Should be called if the platform detects the GL context was lost.
+ auto RebuildLostGLContext() -> void;
+
+ /// Attempt to draw a frame.
+ auto DrawFrame(bool during_resize = false) -> void;
+
+ /// 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.
+ auto RunRenderUpkeepCycle() -> void;
+
+ /// Called by the graphics-server when drawing completes for a frame.
+ virtual auto DidFinishRenderingFrame(FrameDef* frame) -> void;
+
+ /// 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;
+ auto SetProductPrice(const std::string& product, const std::string& price)
+ -> void;
+
+ 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 auto OnBootstrapComplete() -> void;
+
+ // Deferred calls that can be made from other threads.
+
+ auto PushCursorUpdate(bool vis) -> void;
+ auto PushShowOnlineScoreUICall(const std::string& show,
+ const std::string& game,
+ const std::string& game_version) -> void;
+ auto PushGetFriendScoresCall(const std::string& game,
+ const std::string& game_version, void* data)
+ -> void;
+ auto PushSubmitScoreCall(const std::string& game,
+ const std::string& game_version, int64_t score)
+ -> void;
+ auto PushAchievementReportCall(const std::string& achievement) -> void;
+ auto PushGetScoresToBeatCall(const std::string& level,
+ const std::string& config, void* py_callback)
+ -> void;
+ auto PushOpenURLCall(const std::string& url) -> void;
+ auto PushStringEditCall(const std::string& name, const std::string& value,
+ int max_chars) -> void;
+ auto PushSetStressTestingCall(bool enable, int player_count) -> void;
+ auto PushPurchaseCall(const std::string& item) -> void;
+ auto PushRestorePurchasesCall() -> void;
+ auto PushResetAchievementsCall() -> void;
+ auto PushPurchaseAckCall(const std::string& purchase,
+ const std::string& order_id) -> void;
+ auto PushNetworkSetupCall(int port, int telnet_port, bool enable_telnet,
+ const std::string& telnet_password) -> void;
+ auto PushShutdownCompleteCall() -> void;
+
+ private:
+ auto UpdatePauseResume() -> void;
+ auto OnPause() -> void;
+ auto OnResume() -> void;
+ auto ShutdownComplete() -> void;
+ bool done_{};
+ bool server_wrapper_managed_{};
+ bool sys_paused_app_{};
+ bool actually_paused_{};
+ std::unique_ptr stress_test_;
+ millisecs_t last_resize_draw_event_time_{};
+ millisecs_t last_app_resume_time_{};
+ std::unordered_map product_prices_;
+ std::mutex product_prices_mutex_;
+};
+
+} // 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..98ac6baf
--- /dev/null
+++ b/src/ballistica/app/app_config.cc
@@ -0,0 +1,285 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/app/app_config.h"
+
+#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::OptionalFloatValue() const -> std::optional {
+ throw Exception("not an optional 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::DefaultOptionalFloatValue() const
+ -> std::optional {
+ throw Exception("not an optional 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::OptionalFloatEntry : public AppConfig::Entry {
+ public:
+ OptionalFloatEntry() = default;
+ OptionalFloatEntry(const char* name, std::optional default_value)
+ : Entry(name), default_value_(default_value) {}
+ auto GetType() const -> Type override { return Type::kOptionalFloat; }
+ auto Resolve() const -> std::optional {
+ return g_python->GetRawConfigValue(name().c_str(), default_value_);
+ }
+ auto OptionalFloatValue() const -> std::optional override {
+ return Resolve();
+ }
+ auto DefaultOptionalFloatValue() const -> std::optional override {
+ return default_value_;
+ }
+
+ private:
+ std::optional 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);
+
+ optional_float_entries_[OptionalFloatID::kIdleExitMinutes] =
+ OptionalFloatEntry("Idle Exit Minutes", std::optional());
+
+ 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);
+
+ // (default to internal keyboard on iircade; not elsewhere)
+ bool_entries_[BoolID::kAlwaysUseInternalKeyboard] =
+ BoolEntry("Always Use Internal Keyboard", g_buildconfig.iircade_build());
+ 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(OptionalFloatID id) -> std::optional {
+ auto i = optional_float_entries_.find(id);
+ if (i == optional_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..6e3303e7
--- /dev/null
+++ b/src/ballistica/app/app_config.h
@@ -0,0 +1,141 @@
+// 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
+#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 OptionalFloatID {
+ kIdleExitMinutes,
+ 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, kOptionalFloat, 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 OptionalFloatValue() const -> std::optional;
+ virtual auto StringValue() const -> std::string;
+ virtual auto IntValue() const -> int;
+ virtual auto BoolValue() const -> bool;
+ virtual auto DefaultFloatValue() const -> float;
+ virtual auto DefaultOptionalFloatValue() const -> std::optional;
+ 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(OptionalFloatID id) -> std::optional;
+ 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 OptionalFloatEntry;
+ class IntEntry;
+ class BoolEntry;
+ template
+ void CompleteMap(const T& entry_map);
+ void SetupEntries();
+ std::map entries_by_name_;
+ std::map float_entries_;
+ std::map optional_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..bb246033
--- /dev/null
+++ b/src/ballistica/app/app_globals.cc
@@ -0,0 +1,12 @@
+// Released under the MIT License. See LICENSE for details.
+
+#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..62dc2a89
--- /dev/null
+++ b/src/ballistica/app/app_globals.h
@@ -0,0 +1,96 @@
+// 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"
+
+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::unordered_map node_types;
+ std::unordered_map node_types_by_id;
+ std::unordered_map node_message_types;
+ std::vector node_message_formats;
+ 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 exec_command;
+ 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{};
+
+ // Maximum time in milliseconds to buffer game input/output before sending
+ // it over the network.
+ int buffer_time{0};
+
+ // How often we send dynamics resync messages.
+ int dynamics_sync_time{500};
+
+ // How many steps we sample for each bucket.
+ int delay_bucket_samples{60};
+
+ 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::unordered_map thread_name_map;
+#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..817fef47
--- /dev/null
+++ b/src/ballistica/app/headless_app.cc
@@ -0,0 +1,24 @@
+// Released under the MIT License. See LICENSE for details.
+#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) {
+ // Handle a few misc things like stress-test updates.
+ // (SDL builds set up a similar timer so we need to also).
+ // This can probably go away at some point.
+ 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..0dbea11a
--- /dev/null
+++ b/src/ballistica/app/stress_test.cc
@@ -0,0 +1,119 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/app/stress_test.h"
+
+#include "ballistica/graphics/graphics_server.h"
+#include "ballistica/graphics/renderer.h"
+#include "ballistica/input/input.h"
+
+namespace ballistica {
+
+void StressTest::SetStressTesting(bool enable, int 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 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..ae346649
--- /dev/null
+++ b/src/ballistica/app/stress_test.h
@@ -0,0 +1,31 @@
+// 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();
+
+ void SetStressTesting(bool enable, int player_count);
+
+ 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..d305f143
--- /dev/null
+++ b/src/ballistica/app/vr_app.cc
@@ -0,0 +1,110 @@
+// Released under the MIT License. See LICENSE for details.
+#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_
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..3315ff80
--- /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, int 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..48488256
--- /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, int 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..b396f203
--- /dev/null
+++ b/src/ballistica/audio/audio_server.cc
@@ -0,0 +1,1174 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/audio/audio_server.h"
+
+#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;
+
+struct AudioServer::Impl {
+ Impl() = default;
+ ~Impl() = default;
+
+#if BA_ENABLE_AUDIO
+ ALCcontext* alc_context_{};
+#endif
+};
+
+/// 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(impl_->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),
+ impl_{new AudioServer::Impl()}
+// impl_{std::make_unique()}
+{
+ // 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);
+ impl_->alc_context_ = alcCreateContext(device, nullptr);
+ BA_PRECONDITION(impl_->alc_context_);
+ BA_PRECONDITION(alcMakeContextCurrent(impl_->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(impl_->alc_context_);
+ alcDestroyContext(impl_->alc_context_);
+ assert(alcGetError(device) == ALC_NO_ERROR);
+ alcCloseDevice(device);
+ }
+ assert(streaming_sources_.empty());
+ assert(al_source_count_ == 0);
+
+#endif // BA_ENABLE_AUDIO
+ delete impl_;
+}
+
+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..53a5f00e
--- /dev/null
+++ b/src/ballistica/audio/audio_server.h
@@ -0,0 +1,144 @@
+// Released under the MIT License. See LICENSE for details.
+
+#ifndef BALLISTICA_AUDIO_AUDIO_SERVER_H_
+#define BALLISTICA_AUDIO_AUDIO_SERVER_H_
+
+#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_; }
+
+ // 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);
+
+ // 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);
+
+ private:
+ class ThreadSource;
+ struct Impl;
+
+ ~AudioServer() override;
+
+ void SetPaused(bool paused);
+
+ 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);
+
+ // Note: should use unique_ptr for this, but build fails on raspberry pi
+ // (gcc 8.3.0). Works on Ubuntu 9.3 so should try again later.
+ // std::unique_ptr impl_{};
+ Impl* impl_{};
+
+ Timer* process_timer_{};
+ bool have_pending_loads_{};
+ bool paused_{};
+ millisecs_t last_sound_fade_process_time_{};
+
+ 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;
+
+ // NOTE: would use unordered_map here but gcc doesn't seem to allow
+ // forward-declared template params with them.
+ 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_;
+};
+
+} // 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..2f2dd2e8
--- /dev/null
+++ b/src/ballistica/audio/audio_source.cc
@@ -0,0 +1,131 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/audio/audio_source.h"
+
+#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..d44a9982
--- /dev/null
+++ b/src/ballistica/audio/audio_streamer.cc
@@ -0,0 +1,156 @@
+// 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;
+
+ // Suppress 'always returns true' lint.
+ if (explicit_bool(false)) {
+ return false;
+ }
+
+ 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, static_cast(rate));
+ CHECK_AL_ERROR;
+ } else {
+ eof_ = true;
+ }
+
+ // Suppress 'always returns true' lint.
+ if (explicit_bool(false)) {
+ return false;
+ }
+
+ 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..93286491
--- /dev/null
+++ b/src/ballistica/audio/ogg_stream.cc
@@ -0,0 +1,134 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/audio/ogg_stream.h"
+
+#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/ballistica.cc b/src/ballistica/ballistica.cc
new file mode 100644
index 00000000..4e1b5637
--- /dev/null
+++ b/src/ballistica/ballistica.cc
@@ -0,0 +1,300 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/ballistica.h"
+
+#include
+
+#include "ballistica/app/app.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_server.h"
+#include "ballistica/game/account.h"
+#include "ballistica/graphics/graphics_server.h"
+#include "ballistica/media/media_server.h"
+#include "ballistica/networking/network_write_module.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 = 20346;
+const char* kAppVersion = "1.6.0";
+
+// 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{};
+AppInternal* g_app_internal{};
+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 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");
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Phase 1: Create and provision all globals.
+ // -------------------------------------------------------------------------
+
+ g_app_globals = new AppGlobals(argc, argv);
+ g_app_internal = CreateAppInternal();
+ g_platform = Platform::Create();
+ 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.
+ // -------------------------------------------------------------------------
+
+ // Let the app and platform do whatever else it wants here such as adding
+ // initial input devices/etc.
+ g_app->OnBootstrapComplete();
+ g_platform->OnBootstrapComplete();
+
+ // 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();
+
+ // -------------------------------------------------------------------------
+ // 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;
+ }
+ }
+ }
+
+ 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
+ auto 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 GetUIScale() -> 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);
+}
+
+} // 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..c24b109c
--- /dev/null
+++ b/src/ballistica/ballistica.h
@@ -0,0 +1,257 @@
+// 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
+#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;
+
+// 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 kBrpFileID = 83749;
+const int kBobFileID = 45623;
+const int kCobFileID = 13466;
+
+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 AppInternal* g_app_internal;
+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;
+
+/// Internal bits.
+auto CreateAppInternal() -> AppInternal*;
+auto AppInternalInitPythonModule() -> void;
+auto AppInternalPythonPostInit() -> void;
+auto AppInternalHasBlessingHash() -> bool;
+auto AppInternalPutLog(bool fatal) -> bool;
+auto AppInternalAAT() -> void;
+auto AppInternalAATE() -> 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;
+auto AppInternalDirectSendLogs(const std::string& prefix,
+ const std::string& suffix, bool instant,
+ int* result = nullptr) -> void;
+
+/// 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 GetUIScale() -> 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/config/config_cmake.h b/src/ballistica/config/config_cmake.h
new file mode 100644
index 00000000..4c1fdb94
--- /dev/null
+++ b/src/ballistica/config/config_cmake.h
@@ -0,0 +1,87 @@
+// 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"
+#elif __aarch64__
+#define BA_PLATFORM_STRING "arm64_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
+#elif __aarch64__
+#define BA_PLATFORM_STRING "arm64_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
+
+// Include some stuff here for once we get precompiling going.
+#ifdef __cplusplus
+#endif // __cplusplus
+
+// 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..664b7cb2
--- /dev/null
+++ b/src/ballistica/config/config_common.h
@@ -0,0 +1,265 @@
+// 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
+
+// Universal sanity checks.
+#if !BA_DEBUG_BUILD
+#if !NDEBUG
+#error NDEBUG should be defined for all non-debug builds.
+#endif // !NDEBUG
+#endif // !BA_DEBUG_BUILD
+
+// 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_
diff --git a/src/ballistica/core/context.cc b/src/ballistica/core/context.cc
new file mode 100644
index 00000000..e6116655
--- /dev/null
+++ b/src/ballistica/core/context.cc
@@ -0,0 +1,140 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/core/context.h"
+
+#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..73f6c10c
--- /dev/null
+++ b/src/ballistica/core/exception.cc
@@ -0,0 +1,81 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/core/exception.h"
+
+#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..1e231b59
--- /dev/null
+++ b/src/ballistica/core/fatal_error.cc
@@ -0,0 +1,169 @@
+// Released under the MIT License. See LICENSE for details.
+
+#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;
+ }
+ AppInternalDirectSendLogs(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..2eef8180
--- /dev/null
+++ b/src/ballistica/core/inline.cc
@@ -0,0 +1,11 @@
+// Released under the MIT License. See LICENSE for details.
+
+#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..b44bd122
--- /dev/null
+++ b/src/ballistica/core/logging.cc
@@ -0,0 +1,111 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/core/logging.h"
+
+#include
+
+#include "ballistica/app/app_globals.h"
+#include "ballistica/game/game.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;
+ }
+ AppInternalDirectSendLogs(logprefix, logsuffix, false);
+ }
+ }
+ }
+}
+
+} // namespace ballistica
diff --git a/src/ballistica/core/logging.h b/src/ballistica/core/logging.h
new file mode 100644
index 00000000..66d41ed9
--- /dev/null
+++ b/src/ballistica/core/logging.h
@@ -0,0 +1,29 @@
+// 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;
+};
+
+} // 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..ed4a25bb
--- /dev/null
+++ b/src/ballistica/core/macros.cc
@@ -0,0 +1,106 @@
+// Released under the MIT License. See LICENSE for details.
+
+#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..053ddaec
--- /dev/null
+++ b/src/ballistica/core/module.cc
@@ -0,0 +1,48 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/core/module.h"
+
+#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..bfba7dc3
--- /dev/null
+++ b/src/ballistica/core/object.cc
@@ -0,0 +1,229 @@
+// Released under the MIT License. See LICENSE for details.
+
+#include "ballistica/core/object.h"
+
+#include
+#include
+
+#include "ballistica/app/app_globals.h"
+#include "ballistica/generic/utils.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::unordered_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