mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-05 23:13:46 +08:00
got command line args wired up on modular builds
This commit is contained in:
parent
7ed0abb708
commit
d90b1093af
108
.efrocachemap
generated
108
.efrocachemap
generated
@ -421,9 +421,9 @@
|
|||||||
"build/assets/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/74/be/fe45a8417e95b6a2233c51992a26",
|
"build/assets/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/74/be/fe45a8417e95b6a2233c51992a26",
|
||||||
"build/assets/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/48/ab/8cddfcde36a750856f3f81dd20c8",
|
"build/assets/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/48/ab/8cddfcde36a750856f3f81dd20c8",
|
||||||
"build/assets/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/2b/46/8aedfa8741090247f04eb9e6df55",
|
"build/assets/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/2b/46/8aedfa8741090247f04eb9e6df55",
|
||||||
"build/assets/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/b8/5e/c8766634397fb77ae3a407c05d63",
|
"build/assets/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/85/81/9425f358eafcd41e91fb999612ba",
|
||||||
"build/assets/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/6f/38/958616d8cb85916aa8b2bcd84f63",
|
"build/assets/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/db/96/1f7fe0541a31880929e1c17ea957",
|
||||||
"build/assets/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/57/68/d03a19b9035cfae7cdc5377d889a",
|
"build/assets/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/5e/37/3ddcfa6e1f771b74c02298a6599a",
|
||||||
"build/assets/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/b6/00/924583b899165757f412eef0dd01",
|
"build/assets/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/b6/00/924583b899165757f412eef0dd01",
|
||||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/3f/e9/60a8f0ca529aa57b4f9cb7385abc",
|
"build/assets/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/3f/e9/60a8f0ca529aa57b4f9cb7385abc",
|
||||||
"build/assets/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/76/65/32c67af5bd0144c2d63cab0516fa",
|
"build/assets/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/76/65/32c67af5bd0144c2d63cab0516fa",
|
||||||
@ -432,30 +432,30 @@
|
|||||||
"build/assets/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/22/b4/4a33bf81142ba2befad14eb5746e",
|
"build/assets/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/22/b4/4a33bf81142ba2befad14eb5746e",
|
||||||
"build/assets/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/d1/6e/8899211693c20d3b00fc198f58c6",
|
"build/assets/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/d1/6e/8899211693c20d3b00fc198f58c6",
|
||||||
"build/assets/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/0e/39/7cfa5f3fb8cef5f4a64f21cda880",
|
"build/assets/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/0e/39/7cfa5f3fb8cef5f4a64f21cda880",
|
||||||
"build/assets/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/cb/49/1739273c68c82cebca0aee16d6c9",
|
"build/assets/ba_data/data/languages/filipino.json": "https://files.ballistica.net/cache/ba1/58/f3/63cfd8a3ccf0c904ab753d95789b",
|
||||||
"build/assets/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/51/89/e01389f8153497b56fbf0fa069c2",
|
"build/assets/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/51/89/e01389f8153497b56fbf0fa069c2",
|
||||||
"build/assets/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/54/97/54d2a530d825200c6126be56df5c",
|
"build/assets/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/54/97/54d2a530d825200c6126be56df5c",
|
||||||
"build/assets/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/23/6f/8547ba09722b7c7f5b8333986984",
|
"build/assets/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/23/6f/8547ba09722b7c7f5b8333986984",
|
||||||
"build/assets/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/a6/5d/78f912e9a89f98de004405167a6a",
|
"build/assets/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/a6/5d/78f912e9a89f98de004405167a6a",
|
||||||
"build/assets/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/88/ee/0cda537bab9ac827def5e236fe1a",
|
"build/assets/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/88/ee/0cda537bab9ac827def5e236fe1a",
|
||||||
"build/assets/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/a9/b5/10de2f3928d8c1f4887e0975743f",
|
"build/assets/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/79/6a/290a8c44a1e7635208c2ff5fdc6e",
|
||||||
"build/assets/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/58/3b/ae1ecc04375cee089a82359110b7",
|
"build/assets/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/58/3b/ae1ecc04375cee089a82359110b7",
|
||||||
"build/assets/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/67/44/40ada7b8e76adceb2129d7668df6",
|
"build/assets/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/ce/99/027a5d1af17689b4311eafa5ff24",
|
||||||
"build/assets/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/bd/c1/3f8632adda5517059323d928f192",
|
"build/assets/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/bd/c1/3f8632adda5517059323d928f192",
|
||||||
"build/assets/ba_data/data/languages/malay.json": "https://files.ballistica.net/cache/ba1/83/25/62ce997fc70704b9234c95fb2e38",
|
"build/assets/ba_data/data/languages/malay.json": "https://files.ballistica.net/cache/ba1/83/25/62ce997fc70704b9234c95fb2e38",
|
||||||
"build/assets/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/0e/46/0cb71876e02d361e11db64640831",
|
"build/assets/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/51/19/aec9cbb2f8d00f2afaccf5fd5410",
|
||||||
"build/assets/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/a6/a7/4a9a289fa1b97847c9a2578c112b",
|
"build/assets/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/a6/a7/4a9a289fa1b97847c9a2578c112b",
|
||||||
"build/assets/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/99/b2/7c598c90fd522132af3536aef0ee",
|
"build/assets/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/99/b2/7c598c90fd522132af3536aef0ee",
|
||||||
"build/assets/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/ae/eb/dd54f65939c2facc6ac50c117826",
|
"build/assets/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/ae/eb/dd54f65939c2facc6ac50c117826",
|
||||||
"build/assets/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/aa/99/f9f597787fe4e09c8ab53fe2e081",
|
"build/assets/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/aa/99/f9f597787fe4e09c8ab53fe2e081",
|
||||||
"build/assets/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/d7/45/2dd72ac0e51680cb39b5ebaa1c69",
|
"build/assets/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/d7/45/2dd72ac0e51680cb39b5ebaa1c69",
|
||||||
"build/assets/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/27/96/2d53dc3f7dd4e877cd40faafeeef",
|
"build/assets/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/27/96/2d53dc3f7dd4e877cd40faafeeef",
|
||||||
"build/assets/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/45/dd/ce6d9dd446293f5e0ae541f36943",
|
"build/assets/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/87/76/884442afd08b31364dc6a8b0cc16",
|
||||||
"build/assets/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/77/d6/71f10613291ebf9c71da66f18a18",
|
"build/assets/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/77/d6/71f10613291ebf9c71da66f18a18",
|
||||||
"build/assets/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/c7/fc/5ed7bd686839ec1a867763248cf9",
|
"build/assets/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/b9/d4/b4e107456ea6420ee0f9d9d7a03e",
|
||||||
"build/assets/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/33/f6/3753c9af9a5b238d229a0bf23fbc",
|
"build/assets/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/33/f6/3753c9af9a5b238d229a0bf23fbc",
|
||||||
"build/assets/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/0a/97/f1f948f6587ea7d40b639aba67ce",
|
"build/assets/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/0a/97/f1f948f6587ea7d40b639aba67ce",
|
||||||
"build/assets/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/97/4a/399422e3061fdd82f66591283397",
|
"build/assets/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/f7/2e/b51abfbbb56e27866895d7e947d2",
|
||||||
"build/assets/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/b0/e3/d73ccf96c5fa490a54f090ee77a5",
|
"build/assets/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/b0/e3/d73ccf96c5fa490a54f090ee77a5",
|
||||||
"build/assets/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/92/1c/d1e50f60fe3e101f246e172750ba",
|
"build/assets/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/92/1c/d1e50f60fe3e101f246e172750ba",
|
||||||
"build/assets/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/1d/d3/01d490643088a435ce75df971054",
|
"build/assets/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/1d/d3/01d490643088a435ce75df971054",
|
||||||
@ -4068,50 +4068,50 @@
|
|||||||
"build/assets/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/2d/ef/5335207d41b21b9823f6805997f1",
|
"build/assets/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/2d/ef/5335207d41b21b9823f6805997f1",
|
||||||
"build/assets/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/b0/8a/55e2e77623fe657bea24f223a3ae",
|
"build/assets/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/b0/8a/55e2e77623fe657bea24f223a3ae",
|
||||||
"build/assets/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/86/5b/2af4d1e26a1a8073c89acb06e599",
|
"build/assets/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/86/5b/2af4d1e26a1a8073c89acb06e599",
|
||||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/6b/a1/5f560a97ab8641091343c6ee688b",
|
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/3a/79/8c3f90efa237a22e105a984ddc69",
|
||||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/50/dd/86cbb96aca3a339318b00574b2db",
|
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/3f/fe/4c9f0926b60c6a4f5253fde8bb35",
|
||||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/6b/b4/65070558df0a917c9a1aac8bb280",
|
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/98/07/9edc3796de01efe4f2fc30d3fcc9",
|
||||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/93/04/19410cb96b5c12fc2cd20dd9c099",
|
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/37/ba/ee706254c5a21f08b8d4c47bb6e2",
|
||||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/36/69/25b4f3e931ff0add15a975383491",
|
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/1f/9a/33ed6f8e2b78af7b00b2727c6630",
|
||||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/16/68/6011835e4db7927b26761847950b",
|
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/11/f3/0feed20f5d34c23d96b39e5702ae",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/11/bf/aa9df1fd5ae51e9b076a324d8e7a",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/4d/f8/c574339560c3f324d258d73dbe70",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/8a/76/54da9b7ff4d79164d3f4dea2782b",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/bc/b1/66680fead22bdecfcd4c8d825f8b",
|
||||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/4a/08/bf75de3244efe6fc342139a6da32",
|
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/79/44/6cddf6fe194de66ab9576d1d958d",
|
||||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/33/c7/d3534c1d605b5bcc4a541457cde9",
|
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/ef/1c/ddcdbedb47affd72d2f4c5164fd9",
|
||||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/0e/58/c7da77e4c0d031073e4db047e4f3",
|
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/4a/ed/e7b293c3d484257e9c4a6c4b5ce1",
|
||||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/f5/be/f80777972954ebe6fd91b52a6533",
|
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/c1/ed/4691901b692a59e598bd982f6d5b",
|
||||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/e4/20/0f1e3a2e343e48dbe3c3ae8c6ab7",
|
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/02/74/f6091bf03a2de2690ac9de36391a",
|
||||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/23/46/72f453ea380bd5f04957886c2b57",
|
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/fa/8c/79e39ee8297c9946f3dfed5d47c4",
|
||||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/f8/e3/b7bf2bdd4fe4879e8f95bc56073c",
|
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/f0/c4/0554dbc45078ce12e3ab1ab00667",
|
||||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/b5/e6/451f3cc73b5b79d21b19c2416d61",
|
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/2a/c3/4378d0290b122a345787b46ef23c",
|
||||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/b2/0e/778420dfd1a6f81ed457a94f8f1d",
|
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/f1/6a/dcbae2252ce071fd07a350615351",
|
||||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/00/76/0f4dd3bbf7a98f00221307535b4f",
|
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/c2/4b/04f9d9a58fa1d1cefc096cf84e57",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/4d/fe/1d4e9c927e74f900766cb3d3c55f",
|
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/61/8c/ec3c377382be6503836613fe0ae0",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/82/99/e0a873f37e95674f2151ea99bf3d",
|
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/65/8f/25f37b8f6175fbe9274576e2eb4a",
|
||||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/b3/a2/5da0c4dc65f469e4a476e0395eb5",
|
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/50/4e/39e4ff62ab5c2c3e72862c2c0881",
|
||||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/a9/9a/adb83188f9c7d7b51dafd0f8b8a8",
|
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/9d/2b/44367bfb114e7b1148e4e100acd1",
|
||||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/b3/a2/5da0c4dc65f469e4a476e0395eb5",
|
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/50/4e/39e4ff62ab5c2c3e72862c2c0881",
|
||||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/a9/9a/adb83188f9c7d7b51dafd0f8b8a8",
|
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/9d/2b/44367bfb114e7b1148e4e100acd1",
|
||||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/27/f4/269f5d37a8e3938c0acdab299833",
|
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/eb/1a/21761c11e160525903190cfe4ed3",
|
||||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/7b/f3/f98278c9654a972baf65d5f04c12",
|
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/a3/38/2c4abbc88434720311048185fdd1",
|
||||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/27/f4/269f5d37a8e3938c0acdab299833",
|
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/eb/1a/21761c11e160525903190cfe4ed3",
|
||||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/7b/f3/f98278c9654a972baf65d5f04c12",
|
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/a3/38/2c4abbc88434720311048185fdd1",
|
||||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/c7/a2/40728a3ebfb3006c7a47b698214f",
|
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/5f/47/5e5c2e910c783b15c6dcf0d78715",
|
||||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/84/19/a1bbbf42c50329f0cd1377d103bb",
|
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/75/af/1ca3bec27e72101585254739189d",
|
||||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/c7/a2/40728a3ebfb3006c7a47b698214f",
|
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/5f/47/5e5c2e910c783b15c6dcf0d78715",
|
||||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/84/19/a1bbbf42c50329f0cd1377d103bb",
|
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/75/af/1ca3bec27e72101585254739189d",
|
||||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/53/e4/455c68ee50813fe89e3002cf1fe8",
|
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/0b/6e/67ffc264f249cde0044637982bab",
|
||||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/59/fe/a3e369f2db87a305641e74ae70ab",
|
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/06/ab/699f575fabf3819dcf40b4c3125e",
|
||||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/be/df/60063a6845e8654958f1a3e37867",
|
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/b3/27/a8e1a856695454d8b37a7d4f3604",
|
||||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/59/fe/a3e369f2db87a305641e74ae70ab",
|
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/06/ab/699f575fabf3819dcf40b4c3125e",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/91/2f/362a643d543963de549d830fe604",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/b0/37/db1f330cc6d7d6cf987ff55b9ed4",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/2e/d4/67d6c0f9b372eb5cd92c9def6fc8",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/b0/55/536be0beef09a49ecca957ca7318",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/68/8b/d6049425f1069d256abdaf90004c",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/d1/06/f341df353f2df7dbcbc80e2f3987",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/3e/82/f70e75696765ac05875cb5dd778c",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/bd/f3/6f99da945c68fae7f860e69f86c6",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/38/ee/56658557aa2ecabd0d30eb01b68e",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/ea/2d/ca8db3623be87b383486f905f41c",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/6b/4c/568766d02bbca174752488850737",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/1e/fa/09a99039de3bf810e3ed13959416",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/3e/5b/1aa2252706188de69075eb7b3656",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/cb/b0/f146f9d033d82a1d03496360001c",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/ab/a7/21bc5acc8a823bd7c7ec940e97bc",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/e1/5d/453846d79912b5a9a82cb5f8e2f5",
|
||||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/f8/85/fed7f2ed98ff2ba271f9dbe3391c",
|
"src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/f8/85/fed7f2ed98ff2ba271f9dbe3391c",
|
||||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/f8/cd/3af311ac63147882590123b78318",
|
"src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/f8/cd/3af311ac63147882590123b78318",
|
||||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/ee/dd/ad968b176000e31c65be6206a2bc",
|
"src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/ee/dd/ad968b176000e31c65be6206a2bc",
|
||||||
|
|||||||
4
.idea/dictionaries/ericf.xml
generated
4
.idea/dictionaries/ericf.xml
generated
@ -125,6 +125,7 @@
|
|||||||
<w>appletvsimulator</w>
|
<w>appletvsimulator</w>
|
||||||
<w>appmode</w>
|
<w>appmode</w>
|
||||||
<w>appmodeselector</w>
|
<w>appmodeselector</w>
|
||||||
|
<w>appmodule</w>
|
||||||
<w>appname</w>
|
<w>appname</w>
|
||||||
<w>appnameupper</w>
|
<w>appnameupper</w>
|
||||||
<w>appnow</w>
|
<w>appnow</w>
|
||||||
@ -904,6 +905,7 @@
|
|||||||
<w>enumvalue</w>
|
<w>enumvalue</w>
|
||||||
<w>enval</w>
|
<w>enval</w>
|
||||||
<w>envcfg</w>
|
<w>envcfg</w>
|
||||||
|
<w>envconfig</w>
|
||||||
<w>envglobals</w>
|
<w>envglobals</w>
|
||||||
<w>envhash</w>
|
<w>envhash</w>
|
||||||
<w>envname</w>
|
<w>envname</w>
|
||||||
@ -1892,6 +1894,7 @@
|
|||||||
<w>namedarg</w>
|
<w>namedarg</w>
|
||||||
<w>namel</w>
|
<w>namel</w>
|
||||||
<w>namepre</w>
|
<w>namepre</w>
|
||||||
|
<w>namepretty</w>
|
||||||
<w>nametext</w>
|
<w>nametext</w>
|
||||||
<w>nameu</w>
|
<w>nameu</w>
|
||||||
<w>nameval</w>
|
<w>nameval</w>
|
||||||
@ -2432,6 +2435,7 @@
|
|||||||
<w>redist</w>
|
<w>redist</w>
|
||||||
<w>redistributables</w>
|
<w>redistributables</w>
|
||||||
<w>reenabled</w>
|
<w>reenabled</w>
|
||||||
|
<w>reexpose</w>
|
||||||
<w>regionid</w>
|
<w>regionid</w>
|
||||||
<w>registerexecutionpolicyexception</w>
|
<w>registerexecutionpolicyexception</w>
|
||||||
<w>registerwithlaunchservices</w>
|
<w>registerwithlaunchservices</w>
|
||||||
|
|||||||
2
.idea/inspectionProfiles/Default.xml
generated
2
.idea/inspectionProfiles/Default.xml
generated
@ -113,6 +113,8 @@
|
|||||||
<option value="typing_extensions.assert_type" />
|
<option value="typing_extensions.assert_type" />
|
||||||
<option value="float.__getitem__" />
|
<option value="float.__getitem__" />
|
||||||
<option value="pbxproj.pbxsections.PBXGroup.PBXGroup.children" />
|
<option value="pbxproj.pbxsections.PBXGroup.PBXGroup.children" />
|
||||||
|
<option value="bascenev1lib.game.race.Player.__getitem__" />
|
||||||
|
<option value="batools.project._updater._LineChange.__getitem__" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
### 1.7.24 (build 21196, api 8, 2023-07-25)
|
### 1.7.24 (build 21199, api 8, 2023-07-27)
|
||||||
|
|
||||||
|
- Fixed an issue where respawn icons could disappear in epic mode (Thanks for
|
||||||
|
the heads-up Rikko!)
|
||||||
|
- The `BA_ENABLE_IRONY_BUILD_DB` optional build env-var is now
|
||||||
|
`BA_ENABLE_COMPILE_COMMANDS_DB` since this same functionality can be used by
|
||||||
|
clangd or other tools. Originally I was using it for Irony for Emacs; hence
|
||||||
|
the old name.
|
||||||
- Due to the cleanup done in 1.7.20, it is now possible to build and run
|
- Due to the cleanup done in 1.7.20, it is now possible to build and run
|
||||||
Ballistica as a 'pure' Python app consisting of binary Python modules loaded
|
Ballistica as a 'pure' Python app consisting of binary Python modules loaded
|
||||||
by a standard Python interpreter. This new build style is referred to as
|
by a standard Python interpreter. This new build style is referred to as
|
||||||
|
|||||||
48
Makefile
48
Makefile
@ -28,11 +28,11 @@
|
|||||||
help:
|
help:
|
||||||
@tools/pcommand makefile_target_list Makefile
|
@tools/pcommand makefile_target_list Makefile
|
||||||
|
|
||||||
# Set env-var BA_ENABLE_IRONY_BUILD_DB=1 to enable creating/updating a cmake
|
# Set env-var BA_ENABLE_COMPILE_COMMANDS_DB=1 to enable creating/updating a
|
||||||
# compile-commands database for use with irony for emacs (and possibly other
|
# cmake compile-commands database for use with irony for emacs (and possibly
|
||||||
# tools).
|
# other tools).
|
||||||
ifeq ($(BA_ENABLE_IRONY_BUILD_DB),1)
|
ifeq ($(BA_ENABLE_COMPILE_COMMANDS_DB),1)
|
||||||
PREREQ_IRONY_BUILD_DB = .cache/irony/compile_commands.json
|
PREREQ_COMPILE_COMMANDS_DB = .cache/compile_commands_db/compile_commands.json
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Prereq targets that should be safe to run anytime; even if project-files
|
# Prereq targets that should be safe to run anytime; even if project-files
|
||||||
@ -45,7 +45,7 @@ PREREQS_SAFE = .cache/checkenv .dir-locals.el .mypy.ini .pycheckers .pylintrc \
|
|||||||
# fail if the CMakeList files don't match what's on disk. If such a target was
|
# fail if the CMakeList files don't match what's on disk. If such a target was
|
||||||
# included in PREREQS_SAFE it would try to build *before* project updates
|
# included in PREREQS_SAFE it would try to build *before* project updates
|
||||||
# which would leave us stuck in a broken state.
|
# which would leave us stuck in a broken state.
|
||||||
PREREQS_POST_UPDATE_ONLY = $(PREREQ_IRONY_BUILD_DB)
|
PREREQS_POST_UPDATE_ONLY = $(PREREQ_COMPILE_COMMANDS_DB)
|
||||||
|
|
||||||
# Target that should be built before running most any other build.
|
# Target that should be built before running most any other build.
|
||||||
# This installs tool config files, runs environment checks, etc.
|
# This installs tool config files, runs environment checks, etc.
|
||||||
@ -1010,20 +1010,20 @@ CMAKE_BUILD_TYPE ?= Debug
|
|||||||
|
|
||||||
# Build and run the cmake build.
|
# Build and run the cmake build.
|
||||||
cmake: cmake-build
|
cmake: cmake-build
|
||||||
@cd build/cmake/$(CM_BT_LC)/staged && ./ballisticakit
|
cd build/cmake/$(CM_BT_LC)/staged && ./ballisticakit
|
||||||
|
|
||||||
# Build and run the cmake build under the gdb debugger.
|
# Build and run the cmake build under the gdb debugger.
|
||||||
# Sets up the ballistica environment to do things like abort() out to the
|
# Sets up the ballistica environment to do things like abort() out to the
|
||||||
# debugger on errors instead of trying to cleanly exit.
|
# debugger on errors instead of trying to cleanly exit.
|
||||||
cmake-gdb: cmake-build
|
cmake-gdb: cmake-build
|
||||||
@cd build/cmake/$(CM_BT_LC)/staged && \
|
cd build/cmake/$(CM_BT_LC)/staged && \
|
||||||
BA_DEBUGGER_ATTACHED=1 gdb ./ballisticakit
|
BA_DEBUGGER_ATTACHED=1 gdb ./ballisticakit
|
||||||
|
|
||||||
# Build and run the cmake build under the lldb debugger.
|
# Build and run the cmake build under the lldb debugger.
|
||||||
# Sets up the ballistica environment to do things like abort() out to the
|
# Sets up the ballistica environment to do things like abort() out to the
|
||||||
# debugger on errors instead of trying to cleanly exit.
|
# debugger on errors instead of trying to cleanly exit.
|
||||||
cmake-lldb: cmake-build
|
cmake-lldb: cmake-build
|
||||||
@cd build/cmake/$(CM_BT_LC)/staged && \
|
cd build/cmake/$(CM_BT_LC)/staged && \
|
||||||
BA_DEBUGGER_ATTACHED=1 lldb ./ballisticakit
|
BA_DEBUGGER_ATTACHED=1 lldb ./ballisticakit
|
||||||
|
|
||||||
# Build but don't run it.
|
# Build but don't run it.
|
||||||
@ -1045,7 +1045,7 @@ cmake-clean:
|
|||||||
rm -rf build/cmake/$(CM_BT_LC)
|
rm -rf build/cmake/$(CM_BT_LC)
|
||||||
|
|
||||||
cmake-server: cmake-server-build
|
cmake-server: cmake-server-build
|
||||||
@cd build/cmake/server-$(CM_BT_LC)/staged && ./ballisticakit_server
|
cd build/cmake/server-$(CM_BT_LC)/staged && ./ballisticakit_server
|
||||||
|
|
||||||
cmake-server-build: assets-server meta cmake-server-binary
|
cmake-server-build: assets-server meta cmake-server-binary
|
||||||
@$(STAGE_BUILD) -cmakeserver -$(CM_BT_LC) \
|
@$(STAGE_BUILD) -cmakeserver -$(CM_BT_LC) \
|
||||||
@ -1074,7 +1074,7 @@ cmake-modular-build: assets-cmake meta cmake-modular-binary
|
|||||||
Modular build complete: BLU build/cmake/modular-$(CM_BT_LC)/staged
|
Modular build complete: BLU build/cmake/modular-$(CM_BT_LC)/staged
|
||||||
|
|
||||||
cmake-modular: cmake-modular-build
|
cmake-modular: cmake-modular-build
|
||||||
@cd build/cmake/modular-$(CM_BT_LC)/staged && ./ballisticakit
|
cd build/cmake/modular-$(CM_BT_LC)/staged && ./ballisticakit
|
||||||
|
|
||||||
cmake-modular-binary: meta
|
cmake-modular-binary: meta
|
||||||
@tools/pcommand cmake_prep_dir build/cmake/modular-$(CM_BT_LC)
|
@tools/pcommand cmake_prep_dir build/cmake/modular-$(CM_BT_LC)
|
||||||
@ -1089,7 +1089,7 @@ cmake-modular-clean:
|
|||||||
rm -rf build/cmake/modular-$(CM_BT_LC)
|
rm -rf build/cmake/modular-$(CM_BT_LC)
|
||||||
|
|
||||||
cmake-modular-server: cmake-modular-server-build
|
cmake-modular-server: cmake-modular-server-build
|
||||||
@cd build/cmake/modular-server-$(CM_BT_LC)/staged && ./ballisticakit_server
|
cd build/cmake/modular-server-$(CM_BT_LC)/staged && ./ballisticakit_server
|
||||||
|
|
||||||
cmake-modular-server-build: assets-server meta cmake-modular-server-binary
|
cmake-modular-server-build: assets-server meta cmake-modular-server-binary
|
||||||
@$(STAGE_BUILD) -cmakemodularserver -$(CM_BT_LC) \
|
@$(STAGE_BUILD) -cmakemodularserver -$(CM_BT_LC) \
|
||||||
@ -1221,21 +1221,21 @@ ballisticakit-cmake/.clang-format: .clang-format
|
|||||||
@mkdir -p ballisticakit-cmake
|
@mkdir -p ballisticakit-cmake
|
||||||
@cd ballisticakit-cmake && ln -sf ../.clang-format .
|
@cd ballisticakit-cmake && ln -sf ../.clang-format .
|
||||||
|
|
||||||
# Irony in emacs requires us to use cmake to generate a full
|
# Various tools such as Irony for Emacs or clangd make use of a list of
|
||||||
# list of compile commands for all files; lets try to keep it up to date
|
# compile commands for all files; lets try to keep it up to date
|
||||||
# whenever CMakeLists changes.
|
# whenever CMakeLists changes.
|
||||||
.cache/irony/compile_commands.json: ballisticakit-cmake/CMakeLists.txt
|
.cache/compile_commands_db/compile_commands.json: \
|
||||||
@tools/pcommand echo BLU Updating Irony build commands db...
|
ballisticakit-cmake/CMakeLists.txt
|
||||||
@echo Generating Irony compile-commands-list...
|
@tools/pcommand echo BLU Updating compile commands db...
|
||||||
@mkdir -p .cache/irony
|
@mkdir -p .cache/compile_commands_db
|
||||||
@cd .cache/irony \
|
@cd .cache/compile_commands_db \
|
||||||
&& cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug \
|
&& cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug \
|
||||||
$(shell pwd)/ballisticakit-cmake
|
$(shell pwd)/ballisticakit-cmake
|
||||||
@mv .cache/irony/compile_commands.json . \
|
@mv .cache/compile_commands_db/compile_commands.json . \
|
||||||
&& rm -rf .cache/irony \
|
&& rm -rf .cache/compile_commands_db \
|
||||||
&& mkdir .cache/irony \
|
&& mkdir .cache/compile_commands_db \
|
||||||
&& mv compile_commands.json .cache/irony
|
&& mv compile_commands.json .cache/compile_commands_db
|
||||||
@tools/pcommand echo BLU Created Irony build db at $@
|
@tools/pcommand echo BLU Created compile commands db at $@
|
||||||
|
|
||||||
_windows-wsl-build:
|
_windows-wsl-build:
|
||||||
@tools/pcommand wsl_build_check_win_drive
|
@tools/pcommand wsl_build_check_win_drive
|
||||||
|
|||||||
4
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
4
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
@ -83,6 +83,7 @@
|
|||||||
<w>appletvsimulator</w>
|
<w>appletvsimulator</w>
|
||||||
<w>appmode</w>
|
<w>appmode</w>
|
||||||
<w>appmodeselector</w>
|
<w>appmodeselector</w>
|
||||||
|
<w>appmodule</w>
|
||||||
<w>appname</w>
|
<w>appname</w>
|
||||||
<w>appnameupper</w>
|
<w>appnameupper</w>
|
||||||
<w>appnow</w>
|
<w>appnow</w>
|
||||||
@ -549,6 +550,7 @@
|
|||||||
<w>enumvalue</w>
|
<w>enumvalue</w>
|
||||||
<w>enval</w>
|
<w>enval</w>
|
||||||
<w>envcfg</w>
|
<w>envcfg</w>
|
||||||
|
<w>envconfig</w>
|
||||||
<w>envglobals</w>
|
<w>envglobals</w>
|
||||||
<w>envs</w>
|
<w>envs</w>
|
||||||
<w>envval</w>
|
<w>envval</w>
|
||||||
@ -1102,6 +1104,7 @@
|
|||||||
<w>namecap</w>
|
<w>namecap</w>
|
||||||
<w>namel</w>
|
<w>namel</w>
|
||||||
<w>namepre</w>
|
<w>namepre</w>
|
||||||
|
<w>namepretty</w>
|
||||||
<w>nameu</w>
|
<w>nameu</w>
|
||||||
<w>nameval</w>
|
<w>nameval</w>
|
||||||
<w>nbuffer</w>
|
<w>nbuffer</w>
|
||||||
@ -1430,6 +1433,7 @@
|
|||||||
<w>recvfrom</w>
|
<w>recvfrom</w>
|
||||||
<w>redundants</w>
|
<w>redundants</w>
|
||||||
<w>reenabled</w>
|
<w>reenabled</w>
|
||||||
|
<w>reexpose</w>
|
||||||
<w>refcounted</w>
|
<w>refcounted</w>
|
||||||
<w>refl</w>
|
<w>refl</w>
|
||||||
<w>regionid</w>
|
<w>regionid</w>
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
;;; For more information see (info "(emacs) Directory Variables")
|
;;; For more information see (info "(emacs) Directory Variables")
|
||||||
|
|
||||||
;;; Turn flycheck mode on for our c++ stuff and tell jedi where to look for our python stuff.
|
;;; Turn flycheck mode on for our c++ stuff and tell jedi where to look for our python stuff.
|
||||||
((c++-mode (eval . (flycheck-mode)))
|
(
|
||||||
|
;; (c++-mode (eval . (flycheck-mode)))
|
||||||
|
|
||||||
|
|
||||||
(python-ts-mode (jedi:server-args . ("--sys-path" "__EFRO_PROJECT_ROOT__/tools"
|
(python-ts-mode (jedi:server-args . ("--sys-path" "__EFRO_PROJECT_ROOT__/tools"
|
||||||
@ -22,8 +23,18 @@
|
|||||||
(nil . ((projectile-globally-ignored-directories . ("docs"
|
(nil . ((projectile-globally-ignored-directories . ("docs"
|
||||||
"submodules"
|
"submodules"
|
||||||
"src/external"
|
"src/external"
|
||||||
|
"src/assets/ba_data/python-site-packages"
|
||||||
"src/assets/pylib-android"
|
"src/assets/pylib-android"
|
||||||
"src/assets/pylib-apple"
|
"src/assets/pylib-apple"
|
||||||
"src/assets/windows"))))
|
"src/assets/windows"))))
|
||||||
|
|
||||||
|
;; Trying to get project.el to work the same as projectile since its built in.
|
||||||
|
(nil . ((project-vc-ignores . ("docs"
|
||||||
|
"submodules"
|
||||||
|
"src/external"
|
||||||
|
"src/assets/ba_data/python-site-packages"
|
||||||
|
"src/assets/pylib-android"
|
||||||
|
"src/assets/pylib-apple"
|
||||||
|
"src/assets/windows"))))
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@ -41,6 +41,7 @@ from _babase import (
|
|||||||
fade_screen,
|
fade_screen,
|
||||||
fatal_error,
|
fatal_error,
|
||||||
get_display_resolution,
|
get_display_resolution,
|
||||||
|
get_immediate_return_code,
|
||||||
get_low_level_config_value,
|
get_low_level_config_value,
|
||||||
get_max_graphics_quality,
|
get_max_graphics_quality,
|
||||||
get_replays_dir,
|
get_replays_dir,
|
||||||
@ -204,6 +205,7 @@ __all__ = [
|
|||||||
'fatal_error',
|
'fatal_error',
|
||||||
'garbage_collect',
|
'garbage_collect',
|
||||||
'get_display_resolution',
|
'get_display_resolution',
|
||||||
|
'get_immediate_return_code',
|
||||||
'get_ip_address_type',
|
'get_ip_address_type',
|
||||||
'get_low_level_config_value',
|
'get_low_level_config_value',
|
||||||
'get_max_graphics_quality',
|
'get_max_graphics_quality',
|
||||||
|
|||||||
@ -156,11 +156,11 @@ def on_app_launching() -> None:
|
|||||||
|
|
||||||
assert _babase.in_logic_thread()
|
assert _babase.in_logic_thread()
|
||||||
|
|
||||||
# Let the user know if the app Python dir is a custom one.
|
# Let the user know if the app Python dir is a 'user' one.
|
||||||
user_sys_scripts_dir = baenv.get_user_system_scripts_dir()
|
envconfig = baenv.get_config()
|
||||||
if user_sys_scripts_dir is not None:
|
if envconfig.is_user_app_python_dir:
|
||||||
_babase.screenmessage(
|
_babase.screenmessage(
|
||||||
f"Using user system scripts: '{user_sys_scripts_dir}'",
|
f"Using user system scripts: '{envconfig.app_python_dir}'",
|
||||||
color=(0.6, 0.6, 1.0),
|
color=(0.6, 0.6, 1.0),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -24,20 +24,19 @@ from dataclasses import dataclass
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
import __main__
|
import __main__
|
||||||
|
|
||||||
from efro.log import setup_logging, LogLevel
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from efro.log import LogHandler
|
from efro.log import LogHandler
|
||||||
|
|
||||||
# IMPORTANT - It is likely (and in some cases expected) that this
|
# IMPORTANT - It is likely (and in some cases expected) that this
|
||||||
# module's code will be exec'ed multiple times. This is because it is
|
# module's code will be exec'ed multiple times. This is because it is
|
||||||
# the job of this module to set up paths for an engine run, and that may
|
# the job of this module to set up Python paths for an engine run, and
|
||||||
# involve modifying sys.path in such a way that this module resolves to
|
# that may involve modifying sys.path in such a way that this module
|
||||||
# a different path afterwards (for example from
|
# resolves to a different path afterwards (for example from
|
||||||
# /abs/path/to/ba_data/scripts/babase.py to ba_data/scripts/babase.py).
|
# /abs/path/to/ba_data/scripts/babase.py to ba_data/scripts/babase.py).
|
||||||
# This can result in the next import of baenv loading us from our 'new'
|
# This can result in the next import of baenv loading us from our 'new'
|
||||||
# location, which may or may not actually be the same file on disk as
|
# location, which may or may not actually be the same file on disk as
|
||||||
# the old. Either way, however, multiple execs will happen in some form.
|
# the last load. Either way, however, multiple execs will happen in some
|
||||||
|
# form.
|
||||||
#
|
#
|
||||||
# So we need to do a few things to handle that situation gracefully.
|
# So we need to do a few things to handle that situation gracefully.
|
||||||
#
|
#
|
||||||
@ -51,13 +50,13 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
# Build number and version of the ballistica binary we expect to be
|
# Build number and version of the ballistica binary we expect to be
|
||||||
# using.
|
# using.
|
||||||
TARGET_BALLISTICA_BUILD = 21196
|
TARGET_BALLISTICA_BUILD = 21199
|
||||||
TARGET_BALLISTICA_VERSION = '1.7.24'
|
TARGET_BALLISTICA_VERSION = '1.7.24'
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class EnvConfig:
|
class EnvConfig:
|
||||||
"""Environment put together by the configure call."""
|
"""Environment values put together by the configure call."""
|
||||||
|
|
||||||
config_dir: str
|
config_dir: str
|
||||||
data_dir: str
|
data_dir: str
|
||||||
@ -66,49 +65,45 @@ class EnvConfig:
|
|||||||
standard_app_python_dir: str
|
standard_app_python_dir: str
|
||||||
site_python_dir: str | None
|
site_python_dir: str | None
|
||||||
log_handler: LogHandler | None
|
log_handler: LogHandler | None
|
||||||
|
is_user_app_python_dir: bool
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class EnvGlobals:
|
class _EnvGlobals:
|
||||||
"""Our globals we store in the main module."""
|
"""Our globals we store in the main module."""
|
||||||
|
|
||||||
config: EnvConfig | None = None
|
config: EnvConfig | None = None
|
||||||
config_called: bool = False
|
called_configure: bool = False
|
||||||
paths_set_failed: bool = False
|
paths_set_failed: bool = False
|
||||||
user_system_scripts_dir: str | None = None
|
modular_main_called: bool = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls) -> EnvGlobals:
|
def get(cls) -> _EnvGlobals:
|
||||||
"""Create/return our singleton."""
|
"""Create/return our singleton."""
|
||||||
name = '_baenv_globals'
|
name = '_baenv_globals'
|
||||||
envglobals: EnvGlobals | None = getattr(__main__, name, None)
|
envglobals: _EnvGlobals | None = getattr(__main__, name, None)
|
||||||
if envglobals is None:
|
if envglobals is None:
|
||||||
envglobals = EnvGlobals()
|
envglobals = _EnvGlobals()
|
||||||
setattr(__main__, name, envglobals)
|
setattr(__main__, name, envglobals)
|
||||||
return envglobals
|
return envglobals
|
||||||
|
|
||||||
|
|
||||||
|
def did_paths_set_fail() -> bool:
|
||||||
|
"""Did we try to set paths and failed?"""
|
||||||
|
return _EnvGlobals.get().paths_set_failed
|
||||||
|
|
||||||
|
|
||||||
def config_exists() -> bool:
|
def config_exists() -> bool:
|
||||||
"""Has a config been created?"""
|
"""Has a config been created?"""
|
||||||
|
|
||||||
return EnvGlobals.get().config is not None
|
return _EnvGlobals.get().config is not None
|
||||||
|
|
||||||
|
|
||||||
def did_paths_set_fail() -> bool:
|
|
||||||
"""Did we try to set paths and failed?"""
|
|
||||||
return EnvGlobals.get().paths_set_failed
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_system_scripts_dir() -> str | None:
|
|
||||||
"""If there's a custom user system scripts dir in play, return it."""
|
|
||||||
return EnvGlobals.get().user_system_scripts_dir
|
|
||||||
|
|
||||||
|
|
||||||
def get_config() -> EnvConfig:
|
def get_config() -> EnvConfig:
|
||||||
"""Return the active config, creating a default if none exists."""
|
"""Return the active config, creating a default if none exists."""
|
||||||
envglobals = EnvGlobals.get()
|
envglobals = _EnvGlobals.get()
|
||||||
|
|
||||||
if not envglobals.config_called:
|
if not envglobals.called_configure:
|
||||||
configure()
|
configure()
|
||||||
|
|
||||||
config = envglobals.config
|
config = envglobals.config
|
||||||
@ -128,7 +123,7 @@ def configure(
|
|||||||
site_python_dir: str | None = None,
|
site_python_dir: str | None = None,
|
||||||
contains_python_dist: bool = False,
|
contains_python_dist: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Python environment for running a ballistica app.
|
"""Set up the Python environment for running a Ballistica app.
|
||||||
|
|
||||||
This includes things such as Python path wrangling and app directory
|
This includes things such as Python path wrangling and app directory
|
||||||
creation. This should be called before any other ballistica modules
|
creation. This should be called before any other ballistica modules
|
||||||
@ -136,14 +131,14 @@ def configure(
|
|||||||
where those modules get loaded from.
|
where those modules get loaded from.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
envglobals = EnvGlobals.get()
|
envglobals = _EnvGlobals.get()
|
||||||
|
|
||||||
if envglobals.config_called:
|
if envglobals.called_configure:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
'baenv.configure() has already been called;'
|
'baenv.configure() has already been called;'
|
||||||
' it can only be called once.'
|
' it can only be called once.'
|
||||||
)
|
)
|
||||||
envglobals.config_called = True
|
envglobals.called_configure = True
|
||||||
|
|
||||||
# The very first thing we do is set up our logging system and pipe
|
# The very first thing we do is set up our logging system and pipe
|
||||||
# Python's stdout/stderr into it. Then we can at least debug
|
# Python's stdout/stderr into it. Then we can at least debug
|
||||||
@ -167,6 +162,7 @@ def configure(
|
|||||||
data_dir,
|
data_dir,
|
||||||
config_dir,
|
config_dir,
|
||||||
standard_app_python_dir,
|
standard_app_python_dir,
|
||||||
|
is_user_app_python_dir,
|
||||||
) = _setup_paths(
|
) = _setup_paths(
|
||||||
user_python_dir,
|
user_python_dir,
|
||||||
app_python_dir,
|
app_python_dir,
|
||||||
@ -190,6 +186,7 @@ def configure(
|
|||||||
standard_app_python_dir=standard_app_python_dir,
|
standard_app_python_dir=standard_app_python_dir,
|
||||||
site_python_dir=site_python_dir,
|
site_python_dir=site_python_dir,
|
||||||
log_handler=log_handler,
|
log_handler=log_handler,
|
||||||
|
is_user_app_python_dir=is_user_app_python_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -215,6 +212,8 @@ def _calc_data_dir(data_dir: str | None) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def _setup_logging() -> LogHandler:
|
def _setup_logging() -> LogHandler:
|
||||||
|
from efro.log import setup_logging, LogLevel
|
||||||
|
|
||||||
log_handler = setup_logging(
|
log_handler = setup_logging(
|
||||||
log_path=None,
|
log_path=None,
|
||||||
level=LogLevel.DEBUG,
|
level=LogLevel.DEBUG,
|
||||||
@ -249,11 +248,11 @@ def _setup_paths(
|
|||||||
site_python_dir: str | None,
|
site_python_dir: str | None,
|
||||||
data_dir: str | None,
|
data_dir: str | None,
|
||||||
config_dir: str | None,
|
config_dir: str | None,
|
||||||
) -> tuple[str | None, str | None, str | None, str, str, str]:
|
) -> tuple[str | None, str | None, str | None, str, str, str, bool]:
|
||||||
# First a few paths we can ALWAYS calculate since they don't affect
|
# First a few paths we can ALWAYS calculate since they don't affect
|
||||||
# Python imports:
|
# Python imports:
|
||||||
|
|
||||||
envglobals = EnvGlobals.get()
|
envglobals = _EnvGlobals.get()
|
||||||
|
|
||||||
data_dir = _calc_data_dir(data_dir)
|
data_dir = _calc_data_dir(data_dir)
|
||||||
|
|
||||||
@ -264,6 +263,9 @@ def _setup_paths(
|
|||||||
# Standard app-python-dir is simply ba_data/python under data-dir.
|
# Standard app-python-dir is simply ba_data/python under data-dir.
|
||||||
standard_app_python_dir = str(Path(data_dir, 'ba_data', 'python'))
|
standard_app_python_dir = str(Path(data_dir, 'ba_data', 'python'))
|
||||||
|
|
||||||
|
# Whether the final app-dir we're returning is a custom user-owned one.
|
||||||
|
is_user_app_python_dir = False
|
||||||
|
|
||||||
# If _babase has already been imported, there's not much we can do
|
# If _babase has already been imported, there's not much we can do
|
||||||
# at this point aside from complain and inform for next time.
|
# at this point aside from complain and inform for next time.
|
||||||
if '_babase' in sys.modules:
|
if '_babase' in sys.modules:
|
||||||
@ -299,7 +301,8 @@ def _setup_paths(
|
|||||||
# stuff.
|
# stuff.
|
||||||
check_dir = Path(user_python_dir, 'sys', TARGET_BALLISTICA_VERSION)
|
check_dir = Path(user_python_dir, 'sys', TARGET_BALLISTICA_VERSION)
|
||||||
if check_dir.is_dir():
|
if check_dir.is_dir():
|
||||||
envglobals.user_system_scripts_dir = app_python_dir = str(check_dir)
|
app_python_dir = str(check_dir)
|
||||||
|
is_user_app_python_dir = True
|
||||||
|
|
||||||
# Ok, now apply these to sys.path.
|
# Ok, now apply these to sys.path.
|
||||||
|
|
||||||
@ -342,6 +345,7 @@ def _setup_paths(
|
|||||||
data_dir,
|
data_dir,
|
||||||
config_dir,
|
config_dir,
|
||||||
standard_app_python_dir,
|
standard_app_python_dir,
|
||||||
|
is_user_app_python_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -361,16 +365,96 @@ def _setup_dirs(config_dir: str | None, user_python_dir: str | None) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _main() -> None:
|
def extract_arg(args: list[str], names: list[str], is_dir: bool) -> str | None:
|
||||||
# Run a default configure BEFORE importing babase.
|
"""Given a list of args and an arg name, returns a value.
|
||||||
# (may affect where babase comes from).
|
|
||||||
configure()
|
|
||||||
|
|
||||||
import babase
|
The arg flag and value are removed from the arg list. We also check
|
||||||
|
to make sure the path exists.
|
||||||
|
|
||||||
babase.app.run()
|
raises CleanErrors on any problems.
|
||||||
|
"""
|
||||||
|
from efro.error import CleanError
|
||||||
|
|
||||||
|
count = sum(args.count(n) for n in names)
|
||||||
|
if not count:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if count > 1:
|
||||||
|
raise CleanError(f'Arg {names} passed multiple times.')
|
||||||
|
|
||||||
|
for name in names:
|
||||||
|
if name not in args:
|
||||||
|
continue
|
||||||
|
argindex = args.index(name)
|
||||||
|
if argindex + 1 >= len(args):
|
||||||
|
raise CleanError(f'No value passed after {name} arg.')
|
||||||
|
|
||||||
|
val = args[argindex + 1]
|
||||||
|
del args[argindex : argindex + 2]
|
||||||
|
|
||||||
|
if is_dir and not os.path.isdir(val):
|
||||||
|
namepretty = names[0].removeprefix('--')
|
||||||
|
raise CleanError(
|
||||||
|
f"Provided {namepretty} path '{val}' is not a directory."
|
||||||
|
)
|
||||||
|
return val
|
||||||
|
|
||||||
|
raise RuntimeError(f'Expected arg name not found from {names}')
|
||||||
|
|
||||||
|
|
||||||
# Allow exec'ing this module directly to do a standard app run.
|
def _modular_main() -> None:
|
||||||
|
from efro.error import CleanError
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Take note that we're running via modular-main.
|
||||||
|
# The native layer can key off this to know whether it
|
||||||
|
# should apply sys.argv or not.
|
||||||
|
_EnvGlobals.get().modular_main_called = True
|
||||||
|
|
||||||
|
# We run configure() BEFORE importing babase. (part of its job
|
||||||
|
# is to set up where babase and everything else gets loaded
|
||||||
|
# from).
|
||||||
|
|
||||||
|
# We deal with a few key ours here ourself before spinning up
|
||||||
|
# any engine stuff.
|
||||||
|
|
||||||
|
# NOTE: Need to keep these arg long/short versions synced to
|
||||||
|
# those in core_config.cc since they parse the same values (they
|
||||||
|
# just don't handle them).
|
||||||
|
|
||||||
|
args = sys.argv.copy()
|
||||||
|
|
||||||
|
# Our -c arg basically mirrors Python's -c arg. If we get that,
|
||||||
|
# simply exec it and return; no engine stuff.
|
||||||
|
command = extract_arg(args, ['--command', '-c'], is_dir=False)
|
||||||
|
if command is not None:
|
||||||
|
exec(command) # pylint: disable=exec-used
|
||||||
|
return
|
||||||
|
|
||||||
|
config_dir = extract_arg(args, ['--config-dir', '-C'], is_dir=True)
|
||||||
|
data_dir = extract_arg(args, ['--data-dir', '-d'], is_dir=True)
|
||||||
|
mods_dir = extract_arg(args, ['--mods-dir', '-m'], is_dir=True)
|
||||||
|
configure(
|
||||||
|
config_dir=config_dir,
|
||||||
|
data_dir=data_dir,
|
||||||
|
user_python_dir=mods_dir,
|
||||||
|
)
|
||||||
|
|
||||||
|
import babase
|
||||||
|
|
||||||
|
# The engine will have parsed and processed all other args as
|
||||||
|
# part of the above import. If there were errors or args such as
|
||||||
|
# --help which should lead to immediate returns, do so.
|
||||||
|
code = babase.get_immediate_return_code()
|
||||||
|
if code is not None:
|
||||||
|
sys.exit(code)
|
||||||
|
|
||||||
|
babase.app.run()
|
||||||
|
except CleanError as clean_exc:
|
||||||
|
clean_exc.pretty_print()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Exec'ing this module directly will do a standard app run.
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
_main()
|
_modular_main()
|
||||||
|
|||||||
@ -45,6 +45,7 @@ from babase import (
|
|||||||
NodeNotFoundError,
|
NodeNotFoundError,
|
||||||
normalized_color,
|
normalized_color,
|
||||||
NotFoundError,
|
NotFoundError,
|
||||||
|
PlayerNotFoundError,
|
||||||
Plugin,
|
Plugin,
|
||||||
pushcall,
|
pushcall,
|
||||||
safecolor,
|
safecolor,
|
||||||
@ -374,6 +375,7 @@ __all__ = [
|
|||||||
'PlayerDiedMessage',
|
'PlayerDiedMessage',
|
||||||
'PlayerProfilesChangedMessage',
|
'PlayerProfilesChangedMessage',
|
||||||
'PlayerInfo',
|
'PlayerInfo',
|
||||||
|
'PlayerNotFoundError',
|
||||||
'PlayerRecord',
|
'PlayerRecord',
|
||||||
'PlayerScoredMessage',
|
'PlayerScoredMessage',
|
||||||
'Plugin',
|
'Plugin',
|
||||||
|
|||||||
@ -4,14 +4,8 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CoopJoinActivity(bs.JoinActivity):
|
class CoopJoinActivity(bs.JoinActivity):
|
||||||
"""Join-screen for co-op mode."""
|
"""Join-screen for co-op mode."""
|
||||||
@ -46,7 +40,7 @@ class CoopJoinActivity(bs.JoinActivity):
|
|||||||
).autoretain()
|
).autoretain()
|
||||||
ControlsGuide(delay=1.0).autoretain()
|
ControlsGuide(delay=1.0).autoretain()
|
||||||
|
|
||||||
babase.pushcall(self._show_remaining_achievements)
|
bs.pushcall(self._show_remaining_achievements)
|
||||||
|
|
||||||
def _show_remaining_achievements(self) -> None:
|
def _show_remaining_achievements(self) -> None:
|
||||||
from bascenev1lib.actor.text import Text
|
from bascenev1lib.actor.text import Text
|
||||||
@ -70,22 +64,22 @@ class CoopJoinActivity(bs.JoinActivity):
|
|||||||
ts_h_offs = 60
|
ts_h_offs = 60
|
||||||
|
|
||||||
# Show remaining achievements in some cases.
|
# Show remaining achievements in some cases.
|
||||||
if babase.app.classic is not None and not (
|
if bs.app.classic is not None and not (
|
||||||
babase.app.demo_mode or babase.app.arcade_mode
|
bs.app.demo_mode or bs.app.arcade_mode
|
||||||
):
|
):
|
||||||
achievements = [
|
achievements = [
|
||||||
a
|
a
|
||||||
for a in babase.app.classic.ach.achievements_for_coop_level(
|
for a in bs.app.classic.ach.achievements_for_coop_level(
|
||||||
levelname
|
levelname
|
||||||
)
|
)
|
||||||
if not a.complete
|
if not a.complete
|
||||||
]
|
]
|
||||||
have_achievements = bool(achievements)
|
have_achievements = bool(achievements)
|
||||||
achievements = [a for a in achievements if not a.complete]
|
achievements = [a for a in achievements if not a.complete]
|
||||||
vrmode = babase.app.vr_mode
|
vrmode = bs.app.vr_mode
|
||||||
if have_achievements:
|
if have_achievements:
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(resource='achievementsRemainingText'),
|
bs.Lstr(resource='achievementsRemainingText'),
|
||||||
host_only=True,
|
host_only=True,
|
||||||
position=(ts_h_offs - 10, vpos),
|
position=(ts_h_offs - 10, vpos),
|
||||||
transition=Text.Transition.FADE_IN,
|
transition=Text.Transition.FADE_IN,
|
||||||
@ -105,7 +99,7 @@ class CoopJoinActivity(bs.JoinActivity):
|
|||||||
vpos -= 55
|
vpos -= 55
|
||||||
if not achievements:
|
if not achievements:
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(resource='noAchievementsRemainingText'),
|
bs.Lstr(resource='noAchievementsRemainingText'),
|
||||||
host_only=True,
|
host_only=True,
|
||||||
position=(ts_h_offs + 15, vpos + 10),
|
position=(ts_h_offs + 15, vpos + 10),
|
||||||
transition=Text.Transition.FADE_IN,
|
transition=Text.Transition.FADE_IN,
|
||||||
|
|||||||
@ -4,15 +4,9 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
import bascenev1 as bs
|
||||||
|
|
||||||
import babase
|
|
||||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||||
from bascenev1lib.actor.zoomtext import ZoomText
|
from bascenev1lib.actor.zoomtext import ZoomText
|
||||||
import bascenev1 as bs
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DrawScoreScreenActivity(MultiTeamScoreScreenActivity):
|
class DrawScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||||
@ -21,10 +15,10 @@ class DrawScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
default_music = None # Awkward silence...
|
default_music = None # Awkward silence...
|
||||||
|
|
||||||
def on_begin(self) -> None:
|
def on_begin(self) -> None:
|
||||||
babase.set_analytics_screen('Draw Score Screen')
|
bs.set_analytics_screen('Draw Score Screen')
|
||||||
super().on_begin()
|
super().on_begin()
|
||||||
ZoomText(
|
ZoomText(
|
||||||
babase.Lstr(resource='drawText'),
|
bs.Lstr(resource='drawText'),
|
||||||
position=(0, 0),
|
position=(0, 0),
|
||||||
maxwidth=400,
|
maxwidth=400,
|
||||||
shiftposition=(-220, 0),
|
shiftposition=(-220, 0),
|
||||||
|
|||||||
@ -4,16 +4,10 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||||
from bascenev1lib.actor.zoomtext import ZoomText
|
from bascenev1lib.actor.zoomtext import ZoomText
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||||
"""Scorescreen between rounds of a dual-team session."""
|
"""Scorescreen between rounds of a dual-team session."""
|
||||||
@ -24,7 +18,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
assert isinstance(self._winner, bs.SessionTeam)
|
assert isinstance(self._winner, bs.SessionTeam)
|
||||||
|
|
||||||
def on_begin(self) -> None:
|
def on_begin(self) -> None:
|
||||||
babase.set_analytics_screen('Teams Score Screen')
|
bs.set_analytics_screen('Teams Score Screen')
|
||||||
super().on_begin()
|
super().on_begin()
|
||||||
|
|
||||||
height = 130
|
height = 130
|
||||||
@ -37,13 +31,13 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
# 'First to 4'.
|
# 'First to 4'.
|
||||||
session = self.session
|
session = self.session
|
||||||
assert isinstance(session, bs.MultiTeamSession)
|
assert isinstance(session, bs.MultiTeamSession)
|
||||||
if babase.app.lang.get_resource('bestOfUseFirstToInstead'):
|
if bs.app.lang.get_resource('bestOfUseFirstToInstead'):
|
||||||
best_txt = babase.Lstr(
|
best_txt = bs.Lstr(
|
||||||
resource='firstToSeriesText',
|
resource='firstToSeriesText',
|
||||||
subs=[('${COUNT}', str(session.get_series_length() / 2 + 1))],
|
subs=[('${COUNT}', str(session.get_series_length() / 2 + 1))],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
best_txt = babase.Lstr(
|
best_txt = bs.Lstr(
|
||||||
resource='bestOfSeriesText',
|
resource='bestOfSeriesText',
|
||||||
subs=[('${COUNT}', str(session.get_series_length()))],
|
subs=[('${COUNT}', str(session.get_series_length()))],
|
||||||
)
|
)
|
||||||
@ -63,7 +57,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
for team in self.session.sessionteams:
|
for team in self.session.sessionteams:
|
||||||
bs.timer(
|
bs.timer(
|
||||||
i * 0.15 + 0.15,
|
i * 0.15 + 0.15,
|
||||||
babase.WeakCall(
|
bs.WeakCall(
|
||||||
self._show_team_name,
|
self._show_team_name,
|
||||||
vval - i * height,
|
vval - i * height,
|
||||||
team,
|
team,
|
||||||
@ -78,7 +72,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
delay = 1.2
|
delay = 1.2
|
||||||
bs.timer(
|
bs.timer(
|
||||||
i * 0.150 + 0.2,
|
i * 0.150 + 0.2,
|
||||||
babase.WeakCall(
|
bs.WeakCall(
|
||||||
self._show_team_old_score,
|
self._show_team_old_score,
|
||||||
vval - i * height,
|
vval - i * height,
|
||||||
team,
|
team,
|
||||||
@ -89,7 +83,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
|
|
||||||
bs.timer(
|
bs.timer(
|
||||||
i * 0.150 + delay,
|
i * 0.150 + delay,
|
||||||
babase.WeakCall(
|
bs.WeakCall(
|
||||||
self._show_team_score,
|
self._show_team_score,
|
||||||
vval - i * height,
|
vval - i * height,
|
||||||
team,
|
team,
|
||||||
@ -110,7 +104,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
) -> None:
|
) -> None:
|
||||||
del kill_delay # Unused arg.
|
del kill_delay # Unused arg.
|
||||||
ZoomText(
|
ZoomText(
|
||||||
babase.Lstr(value='${A}:', subs=[('${A}', team.name)]),
|
bs.Lstr(value='${A}:', subs=[('${A}', team.name)]),
|
||||||
position=(100, pos_v),
|
position=(100, pos_v),
|
||||||
shiftposition=(-150, pos_v),
|
shiftposition=(-150, pos_v),
|
||||||
shiftdelay=shiftdelay,
|
shiftdelay=shiftdelay,
|
||||||
|
|||||||
@ -4,15 +4,9 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
from bascenev1lib.actor.text import Text
|
from bascenev1lib.actor.text import Text
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MultiTeamJoinActivity(bs.JoinActivity):
|
class MultiTeamJoinActivity(bs.JoinActivity):
|
||||||
"""Join screen for teams sessions."""
|
"""Join screen for teams sessions."""
|
||||||
@ -32,10 +26,10 @@ class MultiTeamJoinActivity(bs.JoinActivity):
|
|||||||
|
|
||||||
# Show info about the next up game.
|
# Show info about the next up game.
|
||||||
self._next_up_text = Text(
|
self._next_up_text = Text(
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
value='${1} ${2}',
|
value='${1} ${2}',
|
||||||
subs=[
|
subs=[
|
||||||
('${1}', babase.Lstr(resource='upFirstText')),
|
('${1}', bs.Lstr(resource='upFirstText')),
|
||||||
('${2}', session.get_next_game_description()),
|
('${2}', session.get_next_game_description()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -72,12 +66,12 @@ class MultiTeamJoinActivity(bs.JoinActivity):
|
|||||||
).autoretain()
|
).autoretain()
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
resource='mustInviteFriendsText',
|
resource='mustInviteFriendsText',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
'${GATHER}',
|
'${GATHER}',
|
||||||
babase.Lstr(resource='gatherWindow.titleText'),
|
bs.Lstr(resource='gatherWindow.titleText'),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -3,16 +3,10 @@
|
|||||||
"""Functionality related to teams mode score screen."""
|
"""Functionality related to teams mode score screen."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
from bascenev1lib.actor.text import Text
|
from bascenev1lib.actor.text import Text
|
||||||
from bascenev1lib.actor.image import Image
|
from bascenev1lib.actor.image import Image
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||||
"""Base class for score screens."""
|
"""Base class for score screens."""
|
||||||
@ -28,12 +22,12 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
|||||||
super().on_begin()
|
super().on_begin()
|
||||||
session = self.session
|
session = self.session
|
||||||
if self._show_up_next and isinstance(session, bs.MultiTeamSession):
|
if self._show_up_next and isinstance(session, bs.MultiTeamSession):
|
||||||
txt = babase.Lstr(
|
txt = bs.Lstr(
|
||||||
value='${A} ${B}',
|
value='${A} ${B}',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
'${A}',
|
'${A}',
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
resource='upNextText',
|
resource='upNextText',
|
||||||
subs=[
|
subs=[
|
||||||
('${COUNT}', str(session.get_game_number() + 1))
|
('${COUNT}', str(session.get_game_number() + 1))
|
||||||
@ -84,7 +78,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
|||||||
return val
|
return val
|
||||||
return p_rec.accumscore
|
return p_rec.accumscore
|
||||||
|
|
||||||
def _get_prec_score_str(p_rec: bs.PlayerRecord) -> str | babase.Lstr:
|
def _get_prec_score_str(p_rec: bs.PlayerRecord) -> str | bs.Lstr:
|
||||||
if is_free_for_all and results is not None:
|
if is_free_for_all and results is not None:
|
||||||
assert isinstance(results, bs.GameResults)
|
assert isinstance(results, bs.GameResults)
|
||||||
assert p_rec.team.activityteam is not None
|
assert p_rec.team.activityteam is not None
|
||||||
@ -135,7 +129,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
|||||||
def _txt(
|
def _txt(
|
||||||
xoffs: float,
|
xoffs: float,
|
||||||
yoffs: float,
|
yoffs: float,
|
||||||
text: babase.Lstr,
|
text: bs.Lstr,
|
||||||
h_align: Text.HAlign = Text.HAlign.RIGHT,
|
h_align: Text.HAlign = Text.HAlign.RIGHT,
|
||||||
extrascale: float = 1.0,
|
extrascale: float = 1.0,
|
||||||
maxwidth: float | None = 120.0,
|
maxwidth: float | None = 120.0,
|
||||||
@ -157,7 +151,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
|||||||
|
|
||||||
session = self.session
|
session = self.session
|
||||||
assert isinstance(session, bs.MultiTeamSession)
|
assert isinstance(session, bs.MultiTeamSession)
|
||||||
tval = babase.Lstr(
|
tval = bs.Lstr(
|
||||||
resource='gameLeadersText',
|
resource='gameLeadersText',
|
||||||
subs=[('${COUNT}', str(session.get_game_number()))],
|
subs=[('${COUNT}', str(session.get_game_number()))],
|
||||||
)
|
)
|
||||||
@ -169,14 +163,12 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
|||||||
extrascale=1.4,
|
extrascale=1.4,
|
||||||
maxwidth=None,
|
maxwidth=None,
|
||||||
)
|
)
|
||||||
_txt(
|
_txt(-15, 4, bs.Lstr(resource='playerText'), h_align=Text.HAlign.LEFT)
|
||||||
-15, 4, babase.Lstr(resource='playerText'), h_align=Text.HAlign.LEFT
|
_txt(180, 4, bs.Lstr(resource='killsText'))
|
||||||
)
|
_txt(280, 4, bs.Lstr(resource='deathsText'), maxwidth=100)
|
||||||
_txt(180, 4, babase.Lstr(resource='killsText'))
|
|
||||||
_txt(280, 4, babase.Lstr(resource='deathsText'), maxwidth=100)
|
|
||||||
|
|
||||||
score_label = 'Score' if results is None else results.score_label
|
score_label = 'Score' if results is None else results.score_label
|
||||||
translated = babase.Lstr(translate=('scoreNames', score_label))
|
translated = bs.Lstr(translate=('scoreNames', score_label))
|
||||||
|
|
||||||
_txt(390, 0, translated)
|
_txt(390, 0, translated)
|
||||||
|
|
||||||
@ -191,7 +183,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
|||||||
topkilledcount = min(topkilledcount, prec.accum_killed_count)
|
topkilledcount = min(topkilledcount, prec.accum_killed_count)
|
||||||
|
|
||||||
def _scoretxt(
|
def _scoretxt(
|
||||||
text: str | babase.Lstr,
|
text: str | bs.Lstr,
|
||||||
x_offs: float,
|
x_offs: float,
|
||||||
highlight: bool,
|
highlight: bool,
|
||||||
delay2: float,
|
delay2: float,
|
||||||
@ -228,7 +220,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
|||||||
transition_delay=tdelay,
|
transition_delay=tdelay,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(value=playerrec.getname(full=True)),
|
bs.Lstr(value=playerrec.getname(full=True)),
|
||||||
maxwidth=160,
|
maxwidth=160,
|
||||||
scale=0.75 * scale,
|
scale=0.75 * scale,
|
||||||
position=(
|
position=(
|
||||||
@ -237,7 +229,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
|||||||
),
|
),
|
||||||
h_align=Text.HAlign.LEFT,
|
h_align=Text.HAlign.LEFT,
|
||||||
v_align=Text.VAlign.CENTER,
|
v_align=Text.VAlign.CENTER,
|
||||||
color=babase.safecolor(playerrec.team.color + (1,)),
|
color=bs.safecolor(playerrec.team.color + (1,)),
|
||||||
transition=Text.Transition.IN_LEFT,
|
transition=Text.Transition.IN_LEFT,
|
||||||
transition_delay=tdelay,
|
transition_delay=tdelay,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
|
|||||||
@ -4,15 +4,9 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||||
"""Final score screen for a team series."""
|
"""Final score screen for a team series."""
|
||||||
@ -35,25 +29,25 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
from bascenev1lib.actor.text import Text
|
from bascenev1lib.actor.text import Text
|
||||||
from bascenev1lib.actor.image import Image
|
from bascenev1lib.actor.image import Image
|
||||||
|
|
||||||
babase.set_analytics_screen(
|
bs.set_analytics_screen(
|
||||||
'FreeForAll Series Victory Screen'
|
'FreeForAll Series Victory Screen'
|
||||||
if self._is_ffa
|
if self._is_ffa
|
||||||
else 'Teams Series Victory Screen'
|
else 'Teams Series Victory Screen'
|
||||||
)
|
)
|
||||||
assert babase.app.classic is not None
|
assert bs.app.classic is not None
|
||||||
if babase.app.ui_v1.uiscale is babase.UIScale.LARGE:
|
if bs.app.ui_v1.uiscale is bs.UIScale.LARGE:
|
||||||
sval = babase.Lstr(resource='pressAnyKeyButtonPlayAgainText')
|
sval = bs.Lstr(resource='pressAnyKeyButtonPlayAgainText')
|
||||||
else:
|
else:
|
||||||
sval = babase.Lstr(resource='pressAnyButtonPlayAgainText')
|
sval = bs.Lstr(resource='pressAnyButtonPlayAgainText')
|
||||||
self._show_up_next = False
|
self._show_up_next = False
|
||||||
self._custom_continue_message = sval
|
self._custom_continue_message = sval
|
||||||
super().on_begin()
|
super().on_begin()
|
||||||
winning_sessionteam = self.settings_raw['winner']
|
winning_sessionteam = self.settings_raw['winner']
|
||||||
|
|
||||||
# Pause a moment before playing victory music.
|
# Pause a moment before playing victory music.
|
||||||
bs.timer(0.6, babase.WeakCall(self._play_victory_music))
|
bs.timer(0.6, bs.WeakCall(self._play_victory_music))
|
||||||
bs.timer(
|
bs.timer(
|
||||||
4.4, babase.WeakCall(self._show_winner, self.settings_raw['winner'])
|
4.4, bs.WeakCall(self._show_winner, self.settings_raw['winner'])
|
||||||
)
|
)
|
||||||
bs.timer(4.6, self._score_display_sound.play)
|
bs.timer(4.6, self._score_display_sound.play)
|
||||||
|
|
||||||
@ -82,19 +76,19 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
tval = 6.4
|
tval = 6.4
|
||||||
t_incr = 0.12
|
t_incr = 0.12
|
||||||
|
|
||||||
always_use_first_to = babase.app.lang.get_resource(
|
always_use_first_to = bs.app.lang.get_resource(
|
||||||
'bestOfUseFirstToInstead'
|
'bestOfUseFirstToInstead'
|
||||||
)
|
)
|
||||||
|
|
||||||
session = self.session
|
session = self.session
|
||||||
if self._is_ffa:
|
if self._is_ffa:
|
||||||
assert isinstance(session, bs.FreeForAllSession)
|
assert isinstance(session, bs.FreeForAllSession)
|
||||||
txt = babase.Lstr(
|
txt = bs.Lstr(
|
||||||
value='${A}:',
|
value='${A}:',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
'${A}',
|
'${A}',
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
resource='firstToFinalText',
|
resource='firstToFinalText',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
@ -115,12 +109,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
# they're not using this language. Should try to come up
|
# they're not using this language. Should try to come up
|
||||||
# with a wording that works everywhere.
|
# with a wording that works everywhere.
|
||||||
if always_use_first_to:
|
if always_use_first_to:
|
||||||
txt = babase.Lstr(
|
txt = bs.Lstr(
|
||||||
value='${A}:',
|
value='${A}:',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
'${A}',
|
'${A}',
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
resource='firstToFinalText',
|
resource='firstToFinalText',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
@ -135,12 +129,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
txt = babase.Lstr(
|
txt = bs.Lstr(
|
||||||
value='${A}:',
|
value='${A}:',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
'${A}',
|
'${A}',
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
resource='bestOfFinalText',
|
resource='bestOfFinalText',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
@ -173,7 +167,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
|
|
||||||
if not self._is_ffa:
|
if not self._is_ffa:
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
resource='gamesToText',
|
resource='gamesToText',
|
||||||
subs=[
|
subs=[
|
||||||
('${WINCOUNT}', str(win_score)),
|
('${WINCOUNT}', str(win_score)),
|
||||||
@ -208,7 +202,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
break
|
break
|
||||||
if mvp is not None:
|
if mvp is not None:
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(resource='mostValuablePlayerText'),
|
bs.Lstr(resource='mostValuablePlayerText'),
|
||||||
color=(0.5, 0.5, 0.5, 1.0),
|
color=(0.5, 0.5, 0.5, 1.0),
|
||||||
v_align=Text.VAlign.CENTER,
|
v_align=Text.VAlign.CENTER,
|
||||||
maxwidth=300,
|
maxwidth=300,
|
||||||
@ -228,13 +222,13 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
).autoretain()
|
).autoretain()
|
||||||
assert mvp_name is not None
|
assert mvp_name is not None
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(value=mvp_name),
|
bs.Lstr(value=mvp_name),
|
||||||
position=(280, ts_height / 2 - 55 + 15 - 5),
|
position=(280, ts_height / 2 - 55 + 15 - 5),
|
||||||
h_align=Text.HAlign.LEFT,
|
h_align=Text.HAlign.LEFT,
|
||||||
v_align=Text.VAlign.CENTER,
|
v_align=Text.VAlign.CENTER,
|
||||||
maxwidth=170,
|
maxwidth=170,
|
||||||
scale=1.3,
|
scale=1.3,
|
||||||
color=babase.safecolor(mvp.team.color + (1,)),
|
color=bs.safecolor(mvp.team.color + (1,)),
|
||||||
transition=Text.Transition.IN_LEFT,
|
transition=Text.Transition.IN_LEFT,
|
||||||
transition_delay=tval,
|
transition_delay=tval,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
@ -249,7 +243,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
most_kills = entry[2].kill_count
|
most_kills = entry[2].kill_count
|
||||||
if mvp is not None:
|
if mvp is not None:
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(resource='mostViolentPlayerText'),
|
bs.Lstr(resource='mostViolentPlayerText'),
|
||||||
color=(0.5, 0.5, 0.5, 1.0),
|
color=(0.5, 0.5, 0.5, 1.0),
|
||||||
v_align=Text.VAlign.CENTER,
|
v_align=Text.VAlign.CENTER,
|
||||||
maxwidth=300,
|
maxwidth=300,
|
||||||
@ -259,12 +253,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
transition_delay=tval,
|
transition_delay=tval,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
value='(${A})',
|
value='(${A})',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
'${A}',
|
'${A}',
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
resource='killsTallyText',
|
resource='killsTallyText',
|
||||||
subs=[('${COUNT}', str(most_kills))],
|
subs=[('${COUNT}', str(most_kills))],
|
||||||
),
|
),
|
||||||
@ -289,12 +283,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
).autoretain()
|
).autoretain()
|
||||||
assert mvp_name is not None
|
assert mvp_name is not None
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(value=mvp_name),
|
bs.Lstr(value=mvp_name),
|
||||||
position=(270, ts_height / 2 - 150 - 30 - 36 + v_extra + 15),
|
position=(270, ts_height / 2 - 150 - 30 - 36 + v_extra + 15),
|
||||||
h_align=Text.HAlign.LEFT,
|
h_align=Text.HAlign.LEFT,
|
||||||
v_align=Text.VAlign.CENTER,
|
v_align=Text.VAlign.CENTER,
|
||||||
maxwidth=180,
|
maxwidth=180,
|
||||||
color=babase.safecolor(mvp.team.color + (1,)),
|
color=bs.safecolor(mvp.team.color + (1,)),
|
||||||
transition=Text.Transition.IN_LEFT,
|
transition=Text.Transition.IN_LEFT,
|
||||||
transition_delay=tval,
|
transition_delay=tval,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
@ -310,7 +304,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
most_killed = entry[2].killed_count
|
most_killed = entry[2].killed_count
|
||||||
if mkp is not None:
|
if mkp is not None:
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(resource='mostViolatedPlayerText'),
|
bs.Lstr(resource='mostViolatedPlayerText'),
|
||||||
color=(0.5, 0.5, 0.5, 1.0),
|
color=(0.5, 0.5, 0.5, 1.0),
|
||||||
v_align=Text.VAlign.CENTER,
|
v_align=Text.VAlign.CENTER,
|
||||||
maxwidth=300,
|
maxwidth=300,
|
||||||
@ -320,12 +314,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
transition_delay=tval,
|
transition_delay=tval,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
value='(${A})',
|
value='(${A})',
|
||||||
subs=[
|
subs=[
|
||||||
(
|
(
|
||||||
'${A}',
|
'${A}',
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
resource='deathsTallyText',
|
resource='deathsTallyText',
|
||||||
subs=[('${COUNT}', str(most_killed))],
|
subs=[('${COUNT}', str(most_killed))],
|
||||||
),
|
),
|
||||||
@ -349,11 +343,11 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
).autoretain()
|
).autoretain()
|
||||||
assert mkp_name is not None
|
assert mkp_name is not None
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(value=mkp_name),
|
bs.Lstr(value=mkp_name),
|
||||||
position=(270, ts_height / 2 - 300 - 30 - 36 + v_extra + 15),
|
position=(270, ts_height / 2 - 300 - 30 - 36 + v_extra + 15),
|
||||||
h_align=Text.HAlign.LEFT,
|
h_align=Text.HAlign.LEFT,
|
||||||
v_align=Text.VAlign.CENTER,
|
v_align=Text.VAlign.CENTER,
|
||||||
color=babase.safecolor(mkp.team.color + (1,)),
|
color=bs.safecolor(mkp.team.color + (1,)),
|
||||||
maxwidth=180,
|
maxwidth=180,
|
||||||
transition=Text.Transition.IN_LEFT,
|
transition=Text.Transition.IN_LEFT,
|
||||||
transition_delay=tval,
|
transition_delay=tval,
|
||||||
@ -363,7 +357,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
# Now show individual scores.
|
# Now show individual scores.
|
||||||
tdelay = tval
|
tdelay = tval
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(resource='finalScoresText'),
|
bs.Lstr(resource='finalScoresText'),
|
||||||
color=(0.5, 0.5, 0.5, 1.0),
|
color=(0.5, 0.5, 0.5, 1.0),
|
||||||
position=(ts_h_offs, ts_height / 2),
|
position=(ts_h_offs, ts_height / 2),
|
||||||
transition=Text.Transition.IN_RIGHT,
|
transition=Text.Transition.IN_RIGHT,
|
||||||
@ -396,17 +390,17 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
transition_delay=tdelay,
|
transition_delay=tdelay,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
Text(
|
Text(
|
||||||
babase.Lstr(value=name),
|
bs.Lstr(value=name),
|
||||||
position=(ts_h_offs - 50, ts_height / 2 + v_offs + 15),
|
position=(ts_h_offs - 50, ts_height / 2 + v_offs + 15),
|
||||||
h_align=Text.HAlign.LEFT,
|
h_align=Text.HAlign.LEFT,
|
||||||
v_align=Text.VAlign.CENTER,
|
v_align=Text.VAlign.CENTER,
|
||||||
maxwidth=180,
|
maxwidth=180,
|
||||||
color=babase.safecolor(prec.team.color + (1,)),
|
color=bs.safecolor(prec.team.color + (1,)),
|
||||||
transition=Text.Transition.IN_RIGHT,
|
transition=Text.Transition.IN_RIGHT,
|
||||||
transition_delay=tdelay,
|
transition_delay=tdelay,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
|
|
||||||
bs.timer(15.0, babase.WeakCall(self._show_tips))
|
bs.timer(15.0, bs.WeakCall(self._show_tips))
|
||||||
|
|
||||||
def _show_tips(self) -> None:
|
def _show_tips(self) -> None:
|
||||||
from bascenev1lib.actor.tipstext import TipsText
|
from bascenev1lib.actor.tipstext import TipsText
|
||||||
@ -443,7 +437,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
assert i.node
|
assert i.node
|
||||||
bs.animate(i.node, 'opacity', {0.0: 0.0, 0.25: 1.0})
|
bs.animate(i.node, 'opacity', {0.0: 0.0, 0.25: 1.0})
|
||||||
ZoomText(
|
ZoomText(
|
||||||
babase.Lstr(
|
bs.Lstr(
|
||||||
value=team.players[0].getname(full=True, icon=False)
|
value=team.players[0].getname(full=True, icon=False)
|
||||||
),
|
),
|
||||||
position=(0, 97 + offs_v),
|
position=(0, 97 + offs_v),
|
||||||
@ -460,7 +454,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
wins_resource = 'seriesWinLine1PlayerText'
|
wins_resource = 'seriesWinLine1PlayerText'
|
||||||
else:
|
else:
|
||||||
wins_resource = 'seriesWinLine1TeamText'
|
wins_resource = 'seriesWinLine1TeamText'
|
||||||
wins_text = babase.Lstr(resource=wins_resource)
|
wins_text = bs.Lstr(resource=wins_resource)
|
||||||
|
|
||||||
# Temp - if these come up as the english default, fall-back to the
|
# Temp - if these come up as the english default, fall-back to the
|
||||||
# unified old form which is more likely to be translated.
|
# unified old form which is more likely to be translated.
|
||||||
@ -473,7 +467,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
|||||||
maxwidth=250,
|
maxwidth=250,
|
||||||
).autoretain()
|
).autoretain()
|
||||||
ZoomText(
|
ZoomText(
|
||||||
babase.Lstr(resource='seriesWinLine2Text'),
|
bs.Lstr(resource='seriesWinLine2Text'),
|
||||||
position=(0, -110 + offs_v),
|
position=(0, -110 + offs_v),
|
||||||
scale=1.0 * s_extra,
|
scale=1.0 * s_extra,
|
||||||
color=team.color,
|
color=team.color,
|
||||||
|
|||||||
@ -6,7 +6,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING, TypeVar, overload
|
from typing import TYPE_CHECKING, TypeVar, overload
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
from bascenev1lib.actor.spaz import Spaz
|
from bascenev1lib.actor.spaz import Spaz
|
||||||
|
|
||||||
@ -99,7 +98,7 @@ class PlayerSpaz(Spaz):
|
|||||||
player: Any = self._player
|
player: Any = self._player
|
||||||
assert isinstance(player, playertype)
|
assert isinstance(player, playertype)
|
||||||
if not player.exists() and doraise:
|
if not player.exists() and doraise:
|
||||||
raise babase.PlayerNotFoundError()
|
raise bs.PlayerNotFoundError()
|
||||||
return player if player.exists() else None
|
return player if player.exists() else None
|
||||||
|
|
||||||
def connect_controls_to_player(
|
def connect_controls_to_player(
|
||||||
@ -129,16 +128,16 @@ class PlayerSpaz(Spaz):
|
|||||||
else:
|
else:
|
||||||
player.resetinput()
|
player.resetinput()
|
||||||
|
|
||||||
player.assigninput(babase.InputType.UP_DOWN, self.on_move_up_down)
|
player.assigninput(bs.InputType.UP_DOWN, self.on_move_up_down)
|
||||||
player.assigninput(babase.InputType.LEFT_RIGHT, self.on_move_left_right)
|
player.assigninput(bs.InputType.LEFT_RIGHT, self.on_move_left_right)
|
||||||
player.assigninput(
|
player.assigninput(
|
||||||
babase.InputType.HOLD_POSITION_PRESS, self.on_hold_position_press
|
bs.InputType.HOLD_POSITION_PRESS, self.on_hold_position_press
|
||||||
)
|
)
|
||||||
player.assigninput(
|
player.assigninput(
|
||||||
babase.InputType.HOLD_POSITION_RELEASE,
|
bs.InputType.HOLD_POSITION_RELEASE,
|
||||||
self.on_hold_position_release,
|
self.on_hold_position_release,
|
||||||
)
|
)
|
||||||
intp = babase.InputType
|
intp = bs.InputType
|
||||||
if enable_jump:
|
if enable_jump:
|
||||||
player.assigninput(intp.JUMP_PRESS, self.on_jump_press)
|
player.assigninput(intp.JUMP_PRESS, self.on_jump_press)
|
||||||
player.assigninput(intp.JUMP_RELEASE, self.on_jump_release)
|
player.assigninput(intp.JUMP_RELEASE, self.on_jump_release)
|
||||||
@ -210,7 +209,7 @@ class PlayerSpaz(Spaz):
|
|||||||
picked_up_by = msg.node.source_player
|
picked_up_by = msg.node.source_player
|
||||||
if picked_up_by:
|
if picked_up_by:
|
||||||
self.last_player_attacked_by = picked_up_by
|
self.last_player_attacked_by = picked_up_by
|
||||||
self.last_attacked_time = babase.apptime()
|
self.last_attacked_time = bs.apptime()
|
||||||
self.last_attacked_type = ('picked_up', 'default')
|
self.last_attacked_type = ('picked_up', 'default')
|
||||||
elif isinstance(msg, bs.StandMessage):
|
elif isinstance(msg, bs.StandMessage):
|
||||||
super().handlemessage(msg) # Augment standard behavior.
|
super().handlemessage(msg) # Augment standard behavior.
|
||||||
@ -248,7 +247,7 @@ class PlayerSpaz(Spaz):
|
|||||||
# something like last_actor_attacked_by to fix that.
|
# something like last_actor_attacked_by to fix that.
|
||||||
if (
|
if (
|
||||||
self.last_player_attacked_by
|
self.last_player_attacked_by
|
||||||
and babase.apptime() - self.last_attacked_time < 4.0
|
and bs.apptime() - self.last_attacked_time < 4.0
|
||||||
):
|
):
|
||||||
killerplayer = self.last_player_attacked_by
|
killerplayer = self.last_player_attacked_by
|
||||||
else:
|
else:
|
||||||
@ -279,7 +278,7 @@ class PlayerSpaz(Spaz):
|
|||||||
source_player = msg.get_source_player(type(self._player))
|
source_player = msg.get_source_player(type(self._player))
|
||||||
if source_player:
|
if source_player:
|
||||||
self.last_player_attacked_by = source_player
|
self.last_player_attacked_by = source_player
|
||||||
self.last_attacked_time = babase.apptime()
|
self.last_attacked_time = bs.apptime()
|
||||||
self.last_attacked_type = (msg.hit_type, msg.hit_subtype)
|
self.last_attacked_type = (msg.hit_type, msg.hit_subtype)
|
||||||
super().handlemessage(msg) # Augment standard behavior.
|
super().handlemessage(msg) # Augment standard behavior.
|
||||||
activity = self._activity()
|
activity = self._activity()
|
||||||
|
|||||||
@ -7,7 +7,6 @@ from __future__ import annotations
|
|||||||
import random
|
import random
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -22,7 +21,7 @@ class PopupText(bs.Actor):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
text: str | babase.Lstr,
|
text: str | bs.Lstr,
|
||||||
position: Sequence[float] = (0.0, 0.0, 0.0),
|
position: Sequence[float] = (0.0, 0.0, 0.0),
|
||||||
color: Sequence[float] = (1.0, 1.0, 1.0, 1.0),
|
color: Sequence[float] = (1.0, 1.0, 1.0, 1.0),
|
||||||
random_offset: float = 0.5,
|
random_offset: float = 0.5,
|
||||||
@ -116,7 +115,7 @@ class PopupText(bs.Actor):
|
|||||||
|
|
||||||
# kill ourself
|
# kill ourself
|
||||||
self._die_timer = bs.Timer(
|
self._die_timer = bs.Timer(
|
||||||
lifespan, babase.WeakCall(self.handlemessage, bs.DieMessage())
|
lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage())
|
||||||
)
|
)
|
||||||
|
|
||||||
def handlemessage(self, msg: Any) -> Any:
|
def handlemessage(self, msg: Any) -> Any:
|
||||||
|
|||||||
@ -5,14 +5,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import weakref
|
import weakref
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class RespawnIcon:
|
class RespawnIcon:
|
||||||
"""An icon with a countdown that appears alongside the screen.
|
"""An icon with a countdown that appears alongside the screen.
|
||||||
@ -22,11 +17,11 @@ class RespawnIcon:
|
|||||||
This is used to indicate that a bascenev1.Player is waiting to respawn.
|
This is used to indicate that a bascenev1.Player is waiting to respawn.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_MASKTEXSTORENAME = babase.storagename('masktex')
|
_MASKTEXSTORENAME = bs.storagename('masktex')
|
||||||
_ICONSSTORENAME = babase.storagename('icons')
|
_ICONSSTORENAME = bs.storagename('icons')
|
||||||
|
|
||||||
def __init__(self, player: bs.Player, respawn_time: float):
|
def __init__(self, player: bs.Player, respawn_time: float):
|
||||||
"""Instantiate with a bascenev1.Player and respawn_time (in seconds)."""
|
"""Instantiate with a Player and respawn_time (in seconds)."""
|
||||||
self._visible = True
|
self._visible = True
|
||||||
|
|
||||||
on_right, offs_extra, respawn_icons = self._get_context(player)
|
on_right, offs_extra, respawn_icons = self._get_context(player)
|
||||||
@ -81,13 +76,13 @@ class RespawnIcon:
|
|||||||
attrs={
|
attrs={
|
||||||
'v_attach': 'top',
|
'v_attach': 'top',
|
||||||
'h_attach': 'right' if on_right else 'left',
|
'h_attach': 'right' if on_right else 'left',
|
||||||
'text': babase.Lstr(value=player.getname()),
|
'text': bs.Lstr(value=player.getname()),
|
||||||
'maxwidth': 100,
|
'maxwidth': 100,
|
||||||
'h_align': 'center',
|
'h_align': 'center',
|
||||||
'v_align': 'center',
|
'v_align': 'center',
|
||||||
'shadow': 1.0,
|
'shadow': 1.0,
|
||||||
'flatness': 1.0,
|
'flatness': 1.0,
|
||||||
'color': babase.safecolor(icon['tint_color']),
|
'color': bs.safecolor(icon['tint_color']),
|
||||||
'scale': 0.5,
|
'scale': 0.5,
|
||||||
'position': npos,
|
'position': npos,
|
||||||
},
|
},
|
||||||
@ -109,7 +104,7 @@ class RespawnIcon:
|
|||||||
'shadow': 0.5,
|
'shadow': 0.5,
|
||||||
'flatness': 0.5,
|
'flatness': 0.5,
|
||||||
'v_attach': 'top',
|
'v_attach': 'top',
|
||||||
'color': babase.safecolor(icon['tint_color']),
|
'color': bs.safecolor(icon['tint_color']),
|
||||||
'text': '',
|
'text': '',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -118,10 +113,10 @@ class RespawnIcon:
|
|||||||
assert self._text.node
|
assert self._text.node
|
||||||
bs.animate(self._text.node, 'scale', {0: 0, 0.1: 0.9})
|
bs.animate(self._text.node, 'scale', {0: 0, 0.1: 0.9})
|
||||||
|
|
||||||
self._respawn_time = babase.apptime() + respawn_time
|
self._respawn_time = bs.time() + respawn_time
|
||||||
self._update()
|
self._update()
|
||||||
self._timer: bs.Timer | None = bs.Timer(
|
self._timer: bs.Timer | None = bs.Timer(
|
||||||
1.0, babase.WeakCall(self._update), repeat=True
|
1.0, bs.WeakCall(self._update), repeat=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -159,7 +154,7 @@ class RespawnIcon:
|
|||||||
return on_right, offs_extra, icons
|
return on_right, offs_extra, icons
|
||||||
|
|
||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
remaining = int(round(self._respawn_time - babase.apptime()))
|
remaining = int(round(self._respawn_time - bs.time()))
|
||||||
if remaining > 0:
|
if remaining > 0:
|
||||||
assert self._text is not None
|
assert self._text is not None
|
||||||
if self._text.node:
|
if self._text.node:
|
||||||
|
|||||||
@ -7,7 +7,6 @@ from __future__ import annotations
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -56,7 +55,7 @@ class Text(bs.Actor):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
text: str | babase.Lstr,
|
text: str | bs.Lstr,
|
||||||
position: tuple[float, float] = (0.0, 0.0),
|
position: tuple[float, float] = (0.0, 0.0),
|
||||||
h_align: HAlign = HAlign.LEFT,
|
h_align: HAlign = HAlign.LEFT,
|
||||||
v_align: VAlign = VAlign.NONE,
|
v_align: VAlign = VAlign.NONE,
|
||||||
@ -219,7 +218,7 @@ class Text(bs.Actor):
|
|||||||
if transition_out_delay is not None:
|
if transition_out_delay is not None:
|
||||||
bs.timer(
|
bs.timer(
|
||||||
transition_delay + transition_out_delay + 1.0,
|
transition_delay + transition_out_delay + 1.0,
|
||||||
babase.WeakCall(self.handlemessage, bs.DieMessage()),
|
bs.WeakCall(self.handlemessage, bs.DieMessage()),
|
||||||
)
|
)
|
||||||
|
|
||||||
def handlemessage(self, msg: Any) -> Any:
|
def handlemessage(self, msg: Any) -> Any:
|
||||||
|
|||||||
@ -6,7 +6,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -34,8 +33,8 @@ class TipsText(bs.Actor):
|
|||||||
'v_attach': 'bottom',
|
'v_attach': 'bottom',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
tval = babase.Lstr(
|
tval = bs.Lstr(
|
||||||
value='${A}:', subs=[('${A}', babase.Lstr(resource='tipText'))]
|
value='${A}:', subs=[('${A}', bs.Lstr(resource='tipText'))]
|
||||||
)
|
)
|
||||||
self.title_node = bs.newnode(
|
self.title_node = bs.newnode(
|
||||||
'text',
|
'text',
|
||||||
@ -54,7 +53,7 @@ class TipsText(bs.Actor):
|
|||||||
self._message_spacing = 3000
|
self._message_spacing = 3000
|
||||||
self._change_timer = bs.Timer(
|
self._change_timer = bs.Timer(
|
||||||
0.001 * (self._message_duration + self._message_spacing),
|
0.001 * (self._message_duration + self._message_spacing),
|
||||||
babase.WeakCall(self.change_phrase),
|
bs.WeakCall(self.change_phrase),
|
||||||
repeat=True,
|
repeat=True,
|
||||||
)
|
)
|
||||||
self._combine = bs.newnode(
|
self._combine = bs.newnode(
|
||||||
@ -70,11 +69,11 @@ class TipsText(bs.Actor):
|
|||||||
"""Switch the visible tip phrase."""
|
"""Switch the visible tip phrase."""
|
||||||
from babase import get_remote_app_name
|
from babase import get_remote_app_name
|
||||||
|
|
||||||
next_tip = babase.Lstr(
|
next_tip = bs.Lstr(
|
||||||
translate=(
|
translate=(
|
||||||
'tips',
|
'tips',
|
||||||
babase.app.classic.get_next_tip()
|
bs.app.classic.get_next_tip()
|
||||||
if babase.app.classic is not None
|
if bs.app.classic is not None
|
||||||
else '',
|
else '',
|
||||||
),
|
),
|
||||||
subs=[('${REMOTE_APP_NAME}', get_remote_app_name())],
|
subs=[('${REMOTE_APP_NAME}', get_remote_app_name())],
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
import logging
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -24,7 +24,7 @@ class ZoomText(bs.Actor):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
text: str | babase.Lstr,
|
text: str | bs.Lstr,
|
||||||
position: tuple[float, float] = (0.0, 0.0),
|
position: tuple[float, float] = (0.0, 0.0),
|
||||||
shiftposition: tuple[float, float] | None = None,
|
shiftposition: tuple[float, float] | None = None,
|
||||||
shiftdelay: float | None = None,
|
shiftdelay: float | None = None,
|
||||||
@ -47,7 +47,7 @@ class ZoomText(bs.Actor):
|
|||||||
if shiftdelay is None:
|
if shiftdelay is None:
|
||||||
shiftdelay = 2.500
|
shiftdelay = 2.500
|
||||||
if shiftdelay < 0.0:
|
if shiftdelay < 0.0:
|
||||||
babase.print_error('got shiftdelay < 0')
|
logging.error('got shiftdelay < 0')
|
||||||
shiftdelay = 0.0
|
shiftdelay = 0.0
|
||||||
self._project_scale = project_scale
|
self._project_scale = project_scale
|
||||||
self.node = bs.newnode(
|
self.node = bs.newnode(
|
||||||
@ -69,7 +69,7 @@ class ZoomText(bs.Actor):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# we never jitter in vr mode..
|
# we never jitter in vr mode..
|
||||||
if babase.app.vr_mode:
|
if bs.app.vr_mode:
|
||||||
jitter = 0.0
|
jitter = 0.0
|
||||||
|
|
||||||
# if they want jitter, animate its position slightly...
|
# if they want jitter, animate its position slightly...
|
||||||
@ -82,14 +82,12 @@ class ZoomText(bs.Actor):
|
|||||||
positionadjusted2 = (shiftposition[0], shiftposition[1] - 100)
|
positionadjusted2 = (shiftposition[0], shiftposition[1] - 100)
|
||||||
bs.timer(
|
bs.timer(
|
||||||
shiftdelay,
|
shiftdelay,
|
||||||
babase.WeakCall(
|
bs.WeakCall(self._shift, positionadjusted, positionadjusted2),
|
||||||
self._shift, positionadjusted, positionadjusted2
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if jitter > 0.0:
|
if jitter > 0.0:
|
||||||
bs.timer(
|
bs.timer(
|
||||||
shiftdelay + 0.25,
|
shiftdelay + 0.25,
|
||||||
babase.WeakCall(
|
bs.WeakCall(
|
||||||
self._jitter, positionadjusted2, jitter * scale
|
self._jitter, positionadjusted2, jitter * scale
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -158,9 +156,7 @@ class ZoomText(bs.Actor):
|
|||||||
|
|
||||||
# if they give us a lifespan, kill ourself down the line
|
# if they give us a lifespan, kill ourself down the line
|
||||||
if lifespan is not None:
|
if lifespan is not None:
|
||||||
bs.timer(
|
bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))
|
||||||
lifespan, babase.WeakCall(self.handlemessage, bs.DieMessage())
|
|
||||||
)
|
|
||||||
|
|
||||||
def handlemessage(self, msg: Any) -> Any:
|
def handlemessage(self, msg: Any) -> Any:
|
||||||
assert not self.expired
|
assert not self.expired
|
||||||
|
|||||||
@ -6,7 +6,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -23,7 +22,7 @@ class SharedObjects:
|
|||||||
standard materials.
|
standard materials.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_STORENAME = babase.storagename()
|
_STORENAME = bs.storagename()
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
activity = bs.getactivity()
|
activity = bs.getactivity()
|
||||||
|
|||||||
@ -4,14 +4,8 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import babase
|
|
||||||
import bascenev1 as bs
|
import bascenev1 as bs
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# FIXME: Could change this to be a classmethod of session types?
|
# FIXME: Could change this to be a classmethod of session types?
|
||||||
class PlaylistTypeVars:
|
class PlaylistTypeVars:
|
||||||
@ -26,26 +20,26 @@ class PlaylistTypeVars:
|
|||||||
self.sessiontype: type[bs.Session]
|
self.sessiontype: type[bs.Session]
|
||||||
|
|
||||||
if issubclass(sessiontype, bs.DualTeamSession):
|
if issubclass(sessiontype, bs.DualTeamSession):
|
||||||
play_mode_name = babase.Lstr(
|
play_mode_name = bs.Lstr(
|
||||||
resource='playModes.teamsText', fallback_resource='teamsText'
|
resource='playModes.teamsText', fallback_resource='teamsText'
|
||||||
)
|
)
|
||||||
self.get_default_list_call = get_default_teams_playlist
|
self.get_default_list_call = get_default_teams_playlist
|
||||||
self.session_type_name = 'bascenev1.DualTeamSession'
|
self.session_type_name = 'bascenev1.DualTeamSession'
|
||||||
self.config_name = 'Team Tournament'
|
self.config_name = 'Team Tournament'
|
||||||
self.window_title_name = babase.Lstr(
|
self.window_title_name = bs.Lstr(
|
||||||
resource='playModes.teamsText', fallback_resource='teamsText'
|
resource='playModes.teamsText', fallback_resource='teamsText'
|
||||||
)
|
)
|
||||||
self.sessiontype = bs.DualTeamSession
|
self.sessiontype = bs.DualTeamSession
|
||||||
|
|
||||||
elif issubclass(sessiontype, bs.FreeForAllSession):
|
elif issubclass(sessiontype, bs.FreeForAllSession):
|
||||||
play_mode_name = babase.Lstr(
|
play_mode_name = bs.Lstr(
|
||||||
resource='playModes.freeForAllText',
|
resource='playModes.freeForAllText',
|
||||||
fallback_resource='freeForAllText',
|
fallback_resource='freeForAllText',
|
||||||
)
|
)
|
||||||
self.get_default_list_call = get_default_free_for_all_playlist
|
self.get_default_list_call = get_default_free_for_all_playlist
|
||||||
self.session_type_name = 'bascenev1.FreeForAllSession'
|
self.session_type_name = 'bascenev1.FreeForAllSession'
|
||||||
self.config_name = 'Free-for-All'
|
self.config_name = 'Free-for-All'
|
||||||
self.window_title_name = babase.Lstr(
|
self.window_title_name = bs.Lstr(
|
||||||
resource='playModes.freeForAllText',
|
resource='playModes.freeForAllText',
|
||||||
fallback_resource='freeForAllText',
|
fallback_resource='freeForAllText',
|
||||||
)
|
)
|
||||||
@ -55,11 +49,11 @@ class PlaylistTypeVars:
|
|||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f'Playlist type vars undefined for sessiontype: {sessiontype}'
|
f'Playlist type vars undefined for sessiontype: {sessiontype}'
|
||||||
)
|
)
|
||||||
self.default_list_name = babase.Lstr(
|
self.default_list_name = bs.Lstr(
|
||||||
resource='defaultGameListNameText',
|
resource='defaultGameListNameText',
|
||||||
subs=[('${PLAYMODE}', play_mode_name)],
|
subs=[('${PLAYMODE}', play_mode_name)],
|
||||||
)
|
)
|
||||||
self.default_new_list_name = babase.Lstr(
|
self.default_new_list_name = bs.Lstr(
|
||||||
resource='defaultNewGameListNameText',
|
resource='defaultNewGameListNameText',
|
||||||
subs=[('${PLAYMODE}', play_mode_name)],
|
subs=[('${PLAYMODE}', play_mode_name)],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import babase
|
import bauiv1 as bui
|
||||||
from bauiv1lib.settings.testing import TestingWindow
|
from bauiv1lib.settings.testing import TestingWindow
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -18,10 +18,10 @@ class VRTestingWindow(TestingWindow):
|
|||||||
|
|
||||||
def __init__(self, transition: str = 'in_right'):
|
def __init__(self, transition: str = 'in_right'):
|
||||||
entries: list[dict[str, Any]] = []
|
entries: list[dict[str, Any]] = []
|
||||||
app = babase.app
|
app = bui.app
|
||||||
assert app.classic is not None
|
assert app.classic is not None
|
||||||
|
|
||||||
# these are gear-vr only
|
# These are gear-vr only.
|
||||||
if (
|
if (
|
||||||
app.classic.platform == 'android'
|
app.classic.platform == 'android'
|
||||||
and app.classic.subplatform == 'oculus'
|
and app.classic.subplatform == 'oculus'
|
||||||
@ -44,16 +44,19 @@ class VRTestingWindow(TestingWindow):
|
|||||||
},
|
},
|
||||||
# {'name':'eyeOffsX','label':'Eye IPD','increment':0.001}
|
# {'name':'eyeOffsX','label':'Eye IPD','increment':0.001}
|
||||||
]
|
]
|
||||||
# cardboard/gearvr get eye offset controls..
|
|
||||||
|
# Cardboard/gearvr get eye offset controls.
|
||||||
# if app.platform == 'android':
|
# if app.platform == 'android':
|
||||||
# entries += [
|
# entries += [
|
||||||
# {'name':'eyeOffsY','label':'Eye Offset Y','increment':0.01},
|
# {'name':'eyeOffsY','label':'Eye Offset Y','increment':0.01},
|
||||||
# {'name':'eyeOffsZ','label':'Eye Offset Z','increment':0.005}]
|
# {'name':'eyeOffsZ','label':'Eye Offset Z','increment':0.005}]
|
||||||
# everyone gets head-scale
|
|
||||||
|
# Everyone gets head-scale.
|
||||||
entries += [
|
entries += [
|
||||||
{'name': 'headScale', 'label': 'Head Scale', 'increment': 1.0}
|
{'name': 'headScale', 'label': 'Head Scale', 'increment': 1.0}
|
||||||
]
|
]
|
||||||
# and everyone gets all these..
|
|
||||||
|
# And everyone gets all these.
|
||||||
entries += [
|
entries += [
|
||||||
{
|
{
|
||||||
'name': 'vrCamOffsetY',
|
'name': 'vrCamOffsetY',
|
||||||
@ -88,7 +91,7 @@ class VRTestingWindow(TestingWindow):
|
|||||||
]
|
]
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
babase.Lstr(resource='settingsWindowAdvanced.vrTestingText'),
|
bui.Lstr(resource='settingsWindowAdvanced.vrTestingText'),
|
||||||
entries,
|
entries,
|
||||||
transition,
|
transition,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,7 +7,6 @@ from __future__ import annotations
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import TYPE_CHECKING, TypeVar, Generic
|
from typing import TYPE_CHECKING, TypeVar, Generic
|
||||||
|
|
||||||
import babase
|
|
||||||
import bauiv1 as bui
|
import bauiv1 as bui
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -35,7 +34,7 @@ class TabRow(Generic[T]):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
parent: bui.Widget,
|
parent: bui.Widget,
|
||||||
tabdefs: list[tuple[T, babase.Lstr]],
|
tabdefs: list[tuple[T, bui.Lstr]],
|
||||||
pos: tuple[float, float],
|
pos: tuple[float, float],
|
||||||
size: tuple[float, float],
|
size: tuple[float, float],
|
||||||
on_select_call: Callable[[T], None] | None = None,
|
on_select_call: Callable[[T], None] | None = None,
|
||||||
@ -58,7 +57,7 @@ class TabRow(Generic[T]):
|
|||||||
size=size,
|
size=size,
|
||||||
label=tab_label,
|
label=tab_label,
|
||||||
enable_sound=False,
|
enable_sound=False,
|
||||||
on_activate_call=babase.Call(
|
on_activate_call=bui.Call(
|
||||||
self._tick_and_call, on_select_call, tab_id
|
self._tick_and_call, on_select_call, tab_id
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -45,7 +45,7 @@ void StressTest::Update() {
|
|||||||
if (t - last_stress_test_update_time_ >= 10000) {
|
if (t - last_stress_test_update_time_ >= 10000) {
|
||||||
if (stress_test_stats_file_ == nullptr) {
|
if (stress_test_stats_file_ == nullptr) {
|
||||||
assert(g_core);
|
assert(g_core);
|
||||||
auto user_python_dir = g_core->platform->GetUserPythonDirectory();
|
auto user_python_dir = g_core->GetUserPythonDirectory();
|
||||||
if (user_python_dir) {
|
if (user_python_dir) {
|
||||||
std::string f_name = *user_python_dir + "/stress_test_stats.csv";
|
std::string f_name = *user_python_dir + "/stress_test_stats.csv";
|
||||||
stress_test_stats_file_ =
|
stress_test_stats_file_ =
|
||||||
|
|||||||
@ -39,7 +39,7 @@ static const bool kShowPruningInfo = false;
|
|||||||
#define PENDING_LOAD_PROCESS_TIME 5
|
#define PENDING_LOAD_PROCESS_TIME 5
|
||||||
|
|
||||||
Assets::Assets() {
|
Assets::Assets() {
|
||||||
asset_paths_.emplace_back(g_core->platform->GetDataDirectory() + BA_DIRSLASH
|
asset_paths_.emplace_back(g_core->GetDataDirectory() + BA_DIRSLASH
|
||||||
+ "ba_data");
|
+ "ba_data");
|
||||||
for (bool& have_pending_load : have_pending_loads_) {
|
for (bool& have_pending_load : have_pending_loads_) {
|
||||||
have_pending_load = false;
|
have_pending_load = false;
|
||||||
|
|||||||
@ -86,7 +86,7 @@ void BaseFeatureSet::OnModuleExec(PyObject* module) {
|
|||||||
|
|
||||||
// Want to run this at the last possible moment before spinning up our
|
// Want to run this at the last possible moment before spinning up our
|
||||||
// BaseFeatureSet. This locks in baenv customizations.
|
// BaseFeatureSet. This locks in baenv customizations.
|
||||||
g_core->python->ApplyBaEnvConfig();
|
g_core->ApplyBaEnvConfig();
|
||||||
|
|
||||||
// Create our feature-set's C++ front-end.
|
// Create our feature-set's C++ front-end.
|
||||||
assert(g_base == nullptr);
|
assert(g_base == nullptr);
|
||||||
|
|||||||
@ -826,8 +826,8 @@ void TextGraphics::LoadGlyphPage(uint32_t index) {
|
|||||||
if (g_glyph_pages[index] == nullptr) {
|
if (g_glyph_pages[index] == nullptr) {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, sizeof(buffer), "%s%sba_data%sfonts%sfontSmall%d.fdata",
|
snprintf(buffer, sizeof(buffer), "%s%sba_data%sfonts%sfontSmall%d.fdata",
|
||||||
g_core->platform->GetDataDirectory().c_str(), BA_DIRSLASH,
|
g_core->GetDataDirectory().c_str(), BA_DIRSLASH, BA_DIRSLASH,
|
||||||
BA_DIRSLASH, BA_DIRSLASH, index);
|
BA_DIRSLASH, index);
|
||||||
FILE* f = g_core->platform->FOpen(buffer, "rb");
|
FILE* f = g_core->platform->FOpen(buffer, "rb");
|
||||||
BA_PRECONDITION(f);
|
BA_PRECONDITION(f);
|
||||||
BA_PRECONDITION(sizeof(TextGraphics::Glyph[2]) == sizeof(float[18]));
|
BA_PRECONDITION(sizeof(TextGraphics::Glyph[2]) == sizeof(float[18]));
|
||||||
|
|||||||
@ -711,12 +711,9 @@ static auto PyEnv(PyObject* self) -> PyObject* {
|
|||||||
default:
|
default:
|
||||||
throw Exception();
|
throw Exception();
|
||||||
}
|
}
|
||||||
std::optional<std::string> user_py_dir =
|
std::optional<std::string> user_py_dir = g_core->GetUserPythonDirectory();
|
||||||
g_core->platform->GetUserPythonDirectory();
|
std::optional<std::string> app_py_dir = g_core->GetAppPythonDirectory();
|
||||||
std::optional<std::string> app_py_dir =
|
std::optional<std::string> site_py_dir = g_core->GetSitePythonDirectory();
|
||||||
g_core->platform->GetAppPythonDirectory();
|
|
||||||
std::optional<std::string> site_py_dir =
|
|
||||||
g_core->platform->GetSitePythonDirectory();
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
PyObject* env = Py_BuildValue(
|
PyObject* env = Py_BuildValue(
|
||||||
@ -772,7 +769,7 @@ static auto PyEnv(PyObject* self) -> PyObject* {
|
|||||||
"device_name",
|
"device_name",
|
||||||
g_core->platform->GetDeviceName().c_str(),
|
g_core->platform->GetDeviceName().c_str(),
|
||||||
"data_directory",
|
"data_directory",
|
||||||
g_core->platform->GetDataDirectory().c_str());
|
g_core->GetDataDirectory().c_str());
|
||||||
// clang-format on
|
// clang-format on
|
||||||
g_base->python->StoreEnv(env);
|
g_base->python->StoreEnv(env);
|
||||||
}
|
}
|
||||||
@ -1449,6 +1446,29 @@ static PyMethodDef PyEmptyAppModeHandleIntentExecDef = {
|
|||||||
"(internal)",
|
"(internal)",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------- get_immediate_return_code ----------------------------
|
||||||
|
|
||||||
|
static auto PyGetImmediateReturnCode(PyObject* self) -> PyObject* {
|
||||||
|
BA_PYTHON_TRY;
|
||||||
|
BA_PRECONDITION(g_core);
|
||||||
|
auto val = g_core->core_config().immediate_return_code;
|
||||||
|
if (!val.has_value()) {
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
return PyLong_FromLong(*val);
|
||||||
|
BA_PYTHON_CATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef PyGetImmediateReturnCodeDef = {
|
||||||
|
"get_immediate_return_code", // name
|
||||||
|
(PyCFunction)PyGetImmediateReturnCode, // method
|
||||||
|
METH_NOARGS, // flags
|
||||||
|
|
||||||
|
"get_immediate_return_code() -> int | None\n"
|
||||||
|
"\n"
|
||||||
|
"(internal)\n",
|
||||||
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
|
auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
|
||||||
@ -1496,6 +1516,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
|
|||||||
PyEmptyAppModeDeactivateDef,
|
PyEmptyAppModeDeactivateDef,
|
||||||
PyEmptyAppModeHandleIntentDefaultDef,
|
PyEmptyAppModeHandleIntentDefaultDef,
|
||||||
PyEmptyAppModeHandleIntentExecDef,
|
PyEmptyAppModeHandleIntentExecDef,
|
||||||
|
PyGetImmediateReturnCodeDef,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -854,7 +854,7 @@ static PyMethodDef PySetPlatformMiscReadValsDef = {
|
|||||||
|
|
||||||
static auto PyGetLogFilePath(PyObject* self, PyObject* args) -> PyObject* {
|
static auto PyGetLogFilePath(PyObject* self, PyObject* args) -> PyObject* {
|
||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
std::string config_dir = g_core->platform->GetConfigDirectory();
|
std::string config_dir = g_core->GetConfigDirectory();
|
||||||
std::string logpath = config_dir + BA_DIRSLASH + "log.json";
|
std::string logpath = config_dir + BA_DIRSLASH + "log.json";
|
||||||
return PyUnicode_FromString(logpath.c_str());
|
return PyUnicode_FromString(logpath.c_str());
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
|
|||||||
@ -15,21 +15,46 @@ CoreFeatureSet* g_core{};
|
|||||||
BaseSoftInterface* g_base_soft{};
|
BaseSoftInterface* g_base_soft{};
|
||||||
|
|
||||||
auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
|
auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
|
||||||
// Only accept a config in monolithic builds if this is the first import.
|
// In monolithic builds we can accept an explicit core-config the first
|
||||||
if (config != nullptr) {
|
// time we're imported.
|
||||||
if (!g_buildconfig.monolithic_build()) {
|
if (g_buildconfig.monolithic_build()) {
|
||||||
FatalError("CoreConfig can only be passed in monolithic builds.");
|
if (config != nullptr) {
|
||||||
}
|
if (g_core != nullptr) {
|
||||||
if (g_core != nullptr) {
|
FatalError(
|
||||||
FatalError("CoreConfig can only be passed on the first import call.");
|
"CoreConfig can only be passed on the first CoreFeatureSet::Import "
|
||||||
}
|
"call.");
|
||||||
|
}
|
||||||
if (g_core == nullptr) {
|
if (g_core == nullptr) {
|
||||||
DoImport(*config);
|
DoImport(*config);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No config passed; use a default.
|
||||||
|
if (g_core == nullptr) {
|
||||||
|
DoImport({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// In modular builds we autogenerate a CoreConfig that takes into
|
||||||
|
// account only env-vars (or env-vars plus Python args if we're being
|
||||||
|
// run via the baenv script).
|
||||||
|
if (config != nullptr) {
|
||||||
|
FatalError("CoreConfig can't be explicitly passed in modular builds.");
|
||||||
|
}
|
||||||
if (g_core == nullptr) {
|
if (g_core == nullptr) {
|
||||||
DoImport({});
|
bool can_do_args = CorePython::WasModularMainCalled();
|
||||||
|
if (can_do_args) {
|
||||||
|
// Wrangle Python's sys.argv into a standard C-style argc/argv so we
|
||||||
|
// can pass to the same handler as the monolithic C route. Note that
|
||||||
|
// a few of the values we parse here (--command, etc) have already
|
||||||
|
// been handled at the Python layer, but we parse them here just the
|
||||||
|
// same so that we have uniform records and invalid-value handling
|
||||||
|
// between monolithic and modular.
|
||||||
|
std::vector<std::string> argbuffer;
|
||||||
|
std::vector<char*> argv = CorePython::FetchPythonArgs(&argbuffer);
|
||||||
|
DoImport(CoreConfig::ForArgsAndEnvVars(argv.size(), argv.data()));
|
||||||
|
} else {
|
||||||
|
DoImport(CoreConfig::ForEnvVars());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return g_core;
|
return g_core;
|
||||||
@ -90,14 +115,88 @@ void CoreFeatureSet::PostInit() {
|
|||||||
// (so that our log handling system is fully bootstrapped), but
|
// (so that our log handling system is fully bootstrapped), but
|
||||||
// technically we can push our log calls out to Python any time now since
|
// technically we can push our log calls out to Python any time now since
|
||||||
// we grabbed the logging calls above. Do so immediately here if asked.
|
// we grabbed the logging calls above. Do so immediately here if asked.
|
||||||
if (!g_core->core_config().hold_early_logs) {
|
if (!core_config_.hold_early_logs) {
|
||||||
python->EnablePythonLoggingCalls();
|
python->EnablePythonLoggingCalls();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: MOVE THIS TO A RUN_APP_TO_COMPLETION() SORT OF PLACE.
|
auto CoreFeatureSet::core_config() const -> const CoreConfig& {
|
||||||
// For now it does the right thing here since all we have is monolithic
|
// Try to make a bit of noise if we're accessed in modular builds before
|
||||||
// builds but this will need to account for more situations later.
|
// baenv values are set, since in that case we won't yet have our final
|
||||||
// python->ReleaseMainThreadGIL();
|
// core-config values. Though we want to keep this to a minimal printf so
|
||||||
|
// we don't interfere with low-level stuff like FatalError handling that
|
||||||
|
// might need core_config access at any time.
|
||||||
|
if (!g_buildconfig.monolithic_build()) {
|
||||||
|
if (!HaveBaEnvVals()) {
|
||||||
|
static bool did_warn = false;
|
||||||
|
if (!did_warn) {
|
||||||
|
did_warn = true;
|
||||||
|
printf(
|
||||||
|
"WARNING: accessing core_config() before baenv values have been "
|
||||||
|
"applied to it.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return core_config_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreFeatureSet::ApplyBaEnvConfig() {
|
||||||
|
auto envcfg =
|
||||||
|
python->objs().Get(core::CorePython::ObjID::kBaEnvGetConfigCall).Call();
|
||||||
|
BA_PRECONDITION_FATAL(envcfg.Exists());
|
||||||
|
|
||||||
|
assert(!have_ba_env_vals_);
|
||||||
|
have_ba_env_vals_ = true;
|
||||||
|
|
||||||
|
// Grab everything baenv shipped us.
|
||||||
|
ba_env_config_dir_ = envcfg.GetAttr("config_dir").ValueAsString();
|
||||||
|
ba_env_data_dir_ = envcfg.GetAttr("data_dir").ValueAsString();
|
||||||
|
ba_env_app_python_dir_ =
|
||||||
|
envcfg.GetAttr("app_python_dir").ValueAsOptionalString();
|
||||||
|
ba_env_user_python_dir_ =
|
||||||
|
envcfg.GetAttr("user_python_dir").ValueAsOptionalString();
|
||||||
|
ba_env_site_python_dir_ =
|
||||||
|
envcfg.GetAttr("site_python_dir").ValueAsOptionalString();
|
||||||
|
|
||||||
|
// Consider app-python-dir to be 'custom' if baenv provided a value for it
|
||||||
|
// AND that value differs from baenv's default.
|
||||||
|
auto standard_app_python_dir =
|
||||||
|
envcfg.GetAttr("standard_app_python_dir").ValueAsString();
|
||||||
|
using_custom_app_python_dir_ =
|
||||||
|
ba_env_app_python_dir_.has_value()
|
||||||
|
&& *ba_env_app_python_dir_ != standard_app_python_dir;
|
||||||
|
|
||||||
|
// Ok, now look for the existence of ba_data in the dir we've got.
|
||||||
|
auto fullpath = ba_env_data_dir_ + BA_DIRSLASH + "ba_data";
|
||||||
|
if (!platform->FilePathExists(fullpath)) {
|
||||||
|
FatalError("ba_data directory not found at '" + fullpath + "'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CoreFeatureSet::GetAppPythonDirectory() -> std::optional<std::string> {
|
||||||
|
BA_PRECONDITION(have_ba_env_vals_);
|
||||||
|
return ba_env_app_python_dir_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CoreFeatureSet::GetUserPythonDirectory() -> std::optional<std::string> {
|
||||||
|
BA_PRECONDITION(have_ba_env_vals_);
|
||||||
|
return ba_env_user_python_dir_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the ballisticakit config dir. This does not vary across versions.
|
||||||
|
auto CoreFeatureSet::GetConfigDirectory() -> std::string {
|
||||||
|
BA_PRECONDITION(have_ba_env_vals_);
|
||||||
|
return ba_env_config_dir_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CoreFeatureSet::GetDataDirectory() -> std::string {
|
||||||
|
BA_PRECONDITION(have_ba_env_vals_);
|
||||||
|
return ba_env_data_dir_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CoreFeatureSet::GetSitePythonDirectory() -> std::optional<std::string> {
|
||||||
|
BA_PRECONDITION(have_ba_env_vals_);
|
||||||
|
return ba_env_site_python_dir_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CoreFeatureSet::CalcBuildSrcDir() -> std::string {
|
auto CoreFeatureSet::CalcBuildSrcDir() -> std::string {
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#ifndef BALLISTICA_CORE_CORE_H_
|
#ifndef BALLISTICA_CORE_CORE_H_
|
||||||
#define BALLISTICA_CORE_CORE_H_
|
#define BALLISTICA_CORE_CORE_H_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -54,13 +55,15 @@ class CoreFeatureSet {
|
|||||||
auto SoftImportBase() -> BaseSoftInterface*;
|
auto SoftImportBase() -> BaseSoftInterface*;
|
||||||
|
|
||||||
/// The core-config we were inited with.
|
/// The core-config we were inited with.
|
||||||
const auto& core_config() const { return core_config_; }
|
auto core_config() const -> const CoreConfig&;
|
||||||
|
|
||||||
/// Start a timer to force-kill our process after the set length of time.
|
/// Start a timer to force-kill our process after the set length of time.
|
||||||
/// Can be used during shutdown or when trying to send a crash-report to
|
/// Can be used during shutdown or when trying to send a crash-report to
|
||||||
/// ensure we don't hang indefinitely.
|
/// ensure we don't hang indefinitely.
|
||||||
void StartSuicideTimer(const std::string& action, millisecs_t delay);
|
void StartSuicideTimer(const std::string& action, millisecs_t delay);
|
||||||
|
|
||||||
|
void ApplyBaEnvConfig();
|
||||||
|
|
||||||
// Call this if the main thread changes.
|
// Call this if the main thread changes.
|
||||||
// Fixme: Should come up with something less hacky feeling.
|
// Fixme: Should come up with something less hacky feeling.
|
||||||
void UpdateMainThreadID();
|
void UpdateMainThreadID();
|
||||||
@ -108,6 +111,38 @@ class CoreFeatureSet {
|
|||||||
legacy_user_agent_string_ = val;
|
legacy_user_agent_string_ = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if baenv values have been locked in: python paths, log
|
||||||
|
/// handling, etc. Early-running code may wish to explicitly avoid making log
|
||||||
|
/// calls until this condition is met to ensure predictable behavior.
|
||||||
|
auto HaveBaEnvVals() const { return have_ba_env_vals_; }
|
||||||
|
|
||||||
|
/// Return the directory where the app expects to find its bundled Python
|
||||||
|
/// files.
|
||||||
|
auto GetAppPythonDirectory() -> std::optional<std::string>;
|
||||||
|
|
||||||
|
/// Return a directory where the local user can manually place Python
|
||||||
|
/// files where they will be accessible by the app. When possible, this
|
||||||
|
/// directory should be in a place easily accessible to the user.
|
||||||
|
auto GetUserPythonDirectory() -> std::optional<std::string>;
|
||||||
|
|
||||||
|
/// Get the root config directory. This dir contains the app config file
|
||||||
|
/// and other data considered essential to the app install. This directory
|
||||||
|
/// should be included in OS backups.
|
||||||
|
auto GetConfigDirectory() -> std::string;
|
||||||
|
|
||||||
|
/// Get the data directory. This dir contains ba_data and possibly other
|
||||||
|
/// platform-specific bits needed for the app to function.
|
||||||
|
auto GetDataDirectory() -> std::string;
|
||||||
|
|
||||||
|
/// Return the directory where bundled 3rd party Python files live.
|
||||||
|
auto GetSitePythonDirectory() -> std::optional<std::string>;
|
||||||
|
|
||||||
|
// Are we using a non-standard app python dir (such as a 'sys' dir within a
|
||||||
|
// user-python-dir).
|
||||||
|
auto using_custom_app_python_dir() const {
|
||||||
|
return using_custom_app_python_dir_;
|
||||||
|
}
|
||||||
|
|
||||||
// Subsystems.
|
// Subsystems.
|
||||||
CorePython* const python;
|
CorePython* const python;
|
||||||
CorePlatform* const platform;
|
CorePlatform* const platform;
|
||||||
@ -159,6 +194,13 @@ class CoreFeatureSet {
|
|||||||
std::mutex app_time_mutex_;
|
std::mutex app_time_mutex_;
|
||||||
std::string legacy_user_agent_string_{
|
std::string legacy_user_agent_string_{
|
||||||
"BA_USER_AGENT_UNSET (" BA_PLATFORM_STRING ")"};
|
"BA_USER_AGENT_UNSET (" BA_PLATFORM_STRING ")"};
|
||||||
|
bool have_ba_env_vals_{};
|
||||||
|
std::optional<std::string> ba_env_app_python_dir_;
|
||||||
|
std::string ba_env_config_dir_;
|
||||||
|
std::optional<std::string> ba_env_user_python_dir_;
|
||||||
|
std::optional<std::string> ba_env_site_python_dir_;
|
||||||
|
std::string ba_env_data_dir_;
|
||||||
|
bool using_custom_app_python_dir_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::core
|
} // namespace ballistica::core
|
||||||
|
|||||||
@ -144,7 +144,7 @@ auto CorePlatform::GetLegacyDeviceUUID() -> const std::string& {
|
|||||||
// in our config dir. This should be globally-unique, but the downside is
|
// in our config dir. This should be globally-unique, but the downside is
|
||||||
// the user can tamper with it.
|
// the user can tamper with it.
|
||||||
if (!have_real_unique_uuid) {
|
if (!have_real_unique_uuid) {
|
||||||
std::string path = GetConfigDirectory() + BA_DIRSLASH + ".bsuuid";
|
std::string path = g_core->GetConfigDirectory() + BA_DIRSLASH + ".bsuuid";
|
||||||
|
|
||||||
if (FILE* f = FOpen(path.c_str(), "rb")) {
|
if (FILE* f = FOpen(path.c_str(), "rb")) {
|
||||||
// There's an existing one; read it.
|
// There's an existing one; read it.
|
||||||
@ -201,13 +201,14 @@ auto CorePlatform::DoGetConfigDirectoryMonolithicDefault()
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto CorePlatform::GetConfigFilePath() -> std::string {
|
auto CorePlatform::GetConfigFilePath() -> std::string {
|
||||||
return GetConfigDirectory() + BA_DIRSLASH + "config.json";
|
return g_core->GetConfigDirectory() + BA_DIRSLASH + "config.json";
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: should make this unnecessary.
|
// FIXME: should make this unnecessary.
|
||||||
auto CorePlatform::GetLowLevelConfigValue(const char* key, int default_value)
|
auto CorePlatform::GetLowLevelConfigValue(const char* key, int default_value)
|
||||||
-> int {
|
-> int {
|
||||||
std::string path = GetConfigDirectory() + BA_DIRSLASH + ".cvar_" + key;
|
std::string path =
|
||||||
|
g_core->GetConfigDirectory() + BA_DIRSLASH + ".cvar_" + key;
|
||||||
int val = default_value;
|
int val = default_value;
|
||||||
FILE* f = FOpen(path.c_str(), "r");
|
FILE* f = FOpen(path.c_str(), "r");
|
||||||
if (f) {
|
if (f) {
|
||||||
@ -225,7 +226,8 @@ auto CorePlatform::GetLowLevelConfigValue(const char* key, int default_value)
|
|||||||
|
|
||||||
// FIXME: should make this unnecessary.
|
// FIXME: should make this unnecessary.
|
||||||
void CorePlatform::SetLowLevelConfigValue(const char* key, int value) {
|
void CorePlatform::SetLowLevelConfigValue(const char* key, int value) {
|
||||||
std::string path = GetConfigDirectory() + BA_DIRSLASH + ".cvar_" + key;
|
std::string path =
|
||||||
|
g_core->GetConfigDirectory() + BA_DIRSLASH + ".cvar_" + key;
|
||||||
std::string out = std::to_string(value);
|
std::string out = std::to_string(value);
|
||||||
FILE* f = FOpen(path.c_str(), "w");
|
FILE* f = FOpen(path.c_str(), "w");
|
||||||
if (f) {
|
if (f) {
|
||||||
@ -238,11 +240,6 @@ void CorePlatform::SetLowLevelConfigValue(const char* key, int value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CorePlatform::GetUserPythonDirectory() -> std::optional<std::string> {
|
|
||||||
BA_PRECONDITION(have_ba_env_vals_);
|
|
||||||
return ba_env_user_python_dir_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CorePlatform::GetVolatileDataDirectory() -> std::string {
|
auto CorePlatform::GetVolatileDataDirectory() -> std::string {
|
||||||
if (!made_volatile_data_dir_) {
|
if (!made_volatile_data_dir_) {
|
||||||
volatile_data_dir_ = GetDefaultVolatileDataDirectory();
|
volatile_data_dir_ = GetDefaultVolatileDataDirectory();
|
||||||
@ -254,23 +251,13 @@ auto CorePlatform::GetVolatileDataDirectory() -> std::string {
|
|||||||
|
|
||||||
auto CorePlatform::GetDefaultVolatileDataDirectory() -> std::string {
|
auto CorePlatform::GetDefaultVolatileDataDirectory() -> std::string {
|
||||||
// By default, stuff this in a subdir under our config dir.
|
// By default, stuff this in a subdir under our config dir.
|
||||||
return GetConfigDirectory() + BA_DIRSLASH + "vdata";
|
return g_core->GetConfigDirectory() + BA_DIRSLASH + "vdata";
|
||||||
}
|
|
||||||
|
|
||||||
auto CorePlatform::GetAppPythonDirectory() -> std::optional<std::string> {
|
|
||||||
BA_PRECONDITION(have_ba_env_vals_);
|
|
||||||
return ba_env_app_python_dir_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CorePlatform::GetSitePythonDirectory() -> std::optional<std::string> {
|
|
||||||
BA_PRECONDITION(have_ba_env_vals_);
|
|
||||||
return ba_env_site_python_dir_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CorePlatform::GetReplaysDir() -> std::string {
|
auto CorePlatform::GetReplaysDir() -> std::string {
|
||||||
static bool made_dir = false;
|
static bool made_dir = false;
|
||||||
if (!made_dir) {
|
if (!made_dir) {
|
||||||
replays_dir_ = GetConfigDirectory() + BA_DIRSLASH + "replays";
|
replays_dir_ = g_core->GetConfigDirectory() + BA_DIRSLASH + "replays";
|
||||||
MakeDir(replays_dir_);
|
MakeDir(replays_dir_);
|
||||||
made_dir = true;
|
made_dir = true;
|
||||||
}
|
}
|
||||||
@ -355,13 +342,6 @@ auto CorePlatform::GetErrnoString() -> std::string {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the ballisticakit config dir
|
|
||||||
// This does not vary across versions.
|
|
||||||
auto CorePlatform::GetConfigDirectory() -> std::string {
|
|
||||||
BA_PRECONDITION(have_ba_env_vals_);
|
|
||||||
return ba_env_config_dir_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CorePlatform::GetConfigDirectoryMonolithicDefault()
|
auto CorePlatform::GetConfigDirectoryMonolithicDefault()
|
||||||
-> std::optional<std::string> {
|
-> std::optional<std::string> {
|
||||||
// CoreConfig value trumps all. Otherwise go with platform-specific default.
|
// CoreConfig value trumps all. Otherwise go with platform-specific default.
|
||||||
@ -371,11 +351,6 @@ auto CorePlatform::GetConfigDirectoryMonolithicDefault()
|
|||||||
return DoGetConfigDirectoryMonolithicDefault();
|
return DoGetConfigDirectoryMonolithicDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CorePlatform::GetDataDirectory() -> std::string {
|
|
||||||
BA_PRECONDITION(have_ba_env_vals_);
|
|
||||||
return ba_env_data_dir_;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CorePlatform::GetDataDirectoryMonolithicDefault() -> std::string {
|
auto CorePlatform::GetDataDirectoryMonolithicDefault() -> std::string {
|
||||||
// CoreConfig arg trumps all. Otherwise ask for platform-specific value.
|
// CoreConfig arg trumps all. Otherwise ask for platform-specific value.
|
||||||
if (g_core->core_config().data_dir.has_value()) {
|
if (g_core->core_config().data_dir.has_value()) {
|
||||||
@ -1216,32 +1191,4 @@ auto CorePlatform::System(const char* cmd) -> int {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorePlatform::SetBaEnvVals(const PythonRef& ref) {
|
|
||||||
assert(!have_ba_env_vals_);
|
|
||||||
have_ba_env_vals_ = true;
|
|
||||||
|
|
||||||
ba_env_config_dir_ = ref.GetAttr("config_dir").ValueAsString();
|
|
||||||
ba_env_data_dir_ = ref.GetAttr("data_dir").ValueAsString();
|
|
||||||
ba_env_app_python_dir_ =
|
|
||||||
ref.GetAttr("app_python_dir").ValueAsOptionalString();
|
|
||||||
ba_env_user_python_dir_ =
|
|
||||||
ref.GetAttr("user_python_dir").ValueAsOptionalString();
|
|
||||||
ba_env_site_python_dir_ =
|
|
||||||
ref.GetAttr("site_python_dir").ValueAsOptionalString();
|
|
||||||
|
|
||||||
// Consider app-python-dir 'custom' if baenv provided a value
|
|
||||||
// for it AND that value differs from baenv's default.
|
|
||||||
auto standard_app_python_dir =
|
|
||||||
ref.GetAttr("standard_app_python_dir").ValueAsString();
|
|
||||||
using_custom_app_python_dir_ =
|
|
||||||
ba_env_app_python_dir_.has_value()
|
|
||||||
&& *ba_env_app_python_dir_ != standard_app_python_dir;
|
|
||||||
|
|
||||||
// Ok, now look for the existence of ba_data in the dir we've got.
|
|
||||||
auto fullpath = ba_env_data_dir_ + BA_DIRSLASH + "ba_data";
|
|
||||||
if (!FilePathExists(fullpath)) {
|
|
||||||
FatalError("ba_data directory not found at '" + fullpath + "'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ballistica::core
|
} // namespace ballistica::core
|
||||||
|
|||||||
@ -141,35 +141,16 @@ class CorePlatform {
|
|||||||
/// etc).
|
/// etc).
|
||||||
virtual auto GetUIScale() -> UIScale;
|
virtual auto GetUIScale() -> UIScale;
|
||||||
|
|
||||||
/// Get the data directory. This dir contains ba_data and possibly other
|
|
||||||
/// platform-specific bits needed for the app to function.
|
|
||||||
auto GetDataDirectory() -> std::string;
|
|
||||||
|
|
||||||
/// Return default DataDirectory value for monolithic builds.
|
/// Return default DataDirectory value for monolithic builds.
|
||||||
auto GetDataDirectoryMonolithicDefault() -> std::string;
|
auto GetDataDirectoryMonolithicDefault() -> std::string;
|
||||||
|
|
||||||
/// Get the root config directory. This dir contains the app config file
|
|
||||||
/// and other data considered essential to the app install. This directory
|
|
||||||
/// should be included in OS backups.
|
|
||||||
auto GetConfigDirectory() -> std::string;
|
|
||||||
auto GetConfigDirectoryMonolithicDefault() -> std::optional<std::string>;
|
auto GetConfigDirectoryMonolithicDefault() -> std::optional<std::string>;
|
||||||
|
|
||||||
/// Get the path of the app config file.
|
/// Get the path of the app config file.
|
||||||
auto GetConfigFilePath() -> std::string;
|
auto GetConfigFilePath() -> std::string;
|
||||||
|
|
||||||
/// Return a directory where the local user can manually place Python
|
|
||||||
/// files where they will be accessible by the app. When possible, this
|
|
||||||
/// directory should be in a place easily accessible to the user.
|
|
||||||
auto GetUserPythonDirectory() -> std::optional<std::string>;
|
|
||||||
auto GetUserPythonDirectoryMonolithicDefault() -> std::optional<std::string>;
|
auto GetUserPythonDirectoryMonolithicDefault() -> std::optional<std::string>;
|
||||||
|
|
||||||
/// Return the directory where the app expects to find its bundled Python
|
|
||||||
/// files.
|
|
||||||
auto GetAppPythonDirectory() -> std::optional<std::string>;
|
|
||||||
|
|
||||||
/// Return the directory where bundled 3rd party Python files live.
|
|
||||||
auto GetSitePythonDirectory() -> std::optional<std::string>;
|
|
||||||
|
|
||||||
/// Get a directory where the app can store internal generated data. This
|
/// Get a directory where the app can store internal generated data. This
|
||||||
/// directory should not be included in backups and the app should remain
|
/// directory should not be included in backups and the app should remain
|
||||||
/// functional if this directory is completely cleared between runs
|
/// functional if this directory is completely cleared between runs
|
||||||
@ -470,20 +451,9 @@ class CorePlatform {
|
|||||||
// return true and set the native full res here. Otherwise return false;
|
// return true and set the native full res here. Otherwise return false;
|
||||||
virtual auto GetDisplayResolution(int* x, int* y) -> bool;
|
virtual auto GetDisplayResolution(int* x, int* y) -> bool;
|
||||||
|
|
||||||
auto using_custom_app_python_dir() const {
|
|
||||||
return using_custom_app_python_dir_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Are we being run from a terminal? (should we show prompts, etc?).
|
/// Are we being run from a terminal? (should we show prompts, etc?).
|
||||||
auto is_stdin_a_terminal() const { return is_stdin_a_terminal_; }
|
auto is_stdin_a_terminal() const { return is_stdin_a_terminal_; }
|
||||||
|
|
||||||
void SetBaEnvVals(const PythonRef& ref);
|
|
||||||
|
|
||||||
/// Return true if baenv values have been locked in: python paths, log
|
|
||||||
/// handling, etc. Early-running code may wish to explicitly avoid making log
|
|
||||||
/// calls until this condition is met to ensure predictable behavior.
|
|
||||||
auto HaveBaEnvVals() const { return have_ba_env_vals_; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Are we being run from a terminal? (should we show prompts, etc?).
|
/// Are we being run from a terminal? (should we show prompts, etc?).
|
||||||
virtual auto GetIsStdinATerminal() -> bool;
|
virtual auto GetIsStdinATerminal() -> bool;
|
||||||
@ -544,7 +514,6 @@ class CorePlatform {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_stdin_a_terminal_{};
|
bool is_stdin_a_terminal_{};
|
||||||
bool using_custom_app_python_dir_{};
|
|
||||||
bool have_has_touchscreen_value_{};
|
bool have_has_touchscreen_value_{};
|
||||||
bool have_touchscreen_{};
|
bool have_touchscreen_{};
|
||||||
bool is_tegra_k1_{};
|
bool is_tegra_k1_{};
|
||||||
@ -553,17 +522,11 @@ class CorePlatform {
|
|||||||
bool made_volatile_data_dir_{};
|
bool made_volatile_data_dir_{};
|
||||||
bool have_device_uuid_{};
|
bool have_device_uuid_{};
|
||||||
bool ran_base_post_init_{};
|
bool ran_base_post_init_{};
|
||||||
bool have_ba_env_vals_{};
|
|
||||||
millisecs_t start_time_millisecs_{};
|
millisecs_t start_time_millisecs_{};
|
||||||
std::string device_name_;
|
std::string device_name_;
|
||||||
std::string legacy_device_uuid_;
|
std::string legacy_device_uuid_;
|
||||||
std::string volatile_data_dir_;
|
std::string volatile_data_dir_;
|
||||||
std::string replays_dir_;
|
std::string replays_dir_;
|
||||||
std::string ba_env_config_dir_;
|
|
||||||
std::string ba_env_data_dir_;
|
|
||||||
std::optional<std::string> ba_env_app_python_dir_;
|
|
||||||
std::optional<std::string> ba_env_user_python_dir_;
|
|
||||||
std::optional<std::string> ba_env_site_python_dir_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ballistica::core
|
} // namespace ballistica::core
|
||||||
|
|||||||
@ -15,13 +15,6 @@ void LowLevelPythonDebugLog(const char* msg) {
|
|||||||
g_core->platform->DebugLog(msg);
|
g_core->platform->DebugLog(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CorePython::ApplyBaEnvConfig() {
|
|
||||||
// Fetch the env-config (creates it if need be).
|
|
||||||
auto envcfg = objs().Get(core::CorePython::ObjID::kBaEnvGetConfigCall).Call();
|
|
||||||
BA_PRECONDITION(envcfg.Exists());
|
|
||||||
g_core->platform->SetBaEnvVals(envcfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CheckPyInitStatus(const char* where, const PyStatus& status) {
|
static void CheckPyInitStatus(const char* where, const PyStatus& status) {
|
||||||
if (PyStatus_Exception(status)) {
|
if (PyStatus_Exception(status)) {
|
||||||
FatalError(std::string("Error in ") + where + ": "
|
FatalError(std::string("Error in ") + where + ": "
|
||||||
@ -337,4 +330,76 @@ void CorePython::LoggingCall(LogLevel loglevel, const std::string& msg) {
|
|||||||
objs().Get(logcallobj).Call(args);
|
objs().Get(logcallobj).Call(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto CorePython::WasModularMainCalled() -> bool {
|
||||||
|
assert(!g_buildconfig.monolithic_build());
|
||||||
|
|
||||||
|
// This gets called in modular builds before anything is inited, so we need to
|
||||||
|
// avoid using anything from g_core or whatnot here; only raw Python stuff.
|
||||||
|
|
||||||
|
PyObject* baenv = PyImport_ImportModule("baenv");
|
||||||
|
if (!baenv) {
|
||||||
|
FatalError("Unable to import baenv module.");
|
||||||
|
}
|
||||||
|
PyObject* env_globals_class = PyObject_GetAttrString(baenv, "_EnvGlobals");
|
||||||
|
if (!env_globals_class) {
|
||||||
|
FatalError("_EnvGlobals class not found in baenv.");
|
||||||
|
}
|
||||||
|
PyObject* get_call = PyObject_GetAttrString(env_globals_class, "get");
|
||||||
|
if (!get_call) {
|
||||||
|
FatalError("get() call not found on baenv._EnvGlobals.");
|
||||||
|
}
|
||||||
|
PyObject* env_globals_instance = PyObject_CallNoArgs(get_call);
|
||||||
|
if (!get_call) {
|
||||||
|
FatalError("baenv._EnvGlobals.get() call failed.");
|
||||||
|
}
|
||||||
|
PyObject* modular_main_called =
|
||||||
|
PyObject_GetAttrString(env_globals_instance, "modular_main_called");
|
||||||
|
if (!modular_main_called || !PyBool_Check(modular_main_called)) {
|
||||||
|
FatalError("modular_main_called bool not found on baenv _EnvGlobals.");
|
||||||
|
}
|
||||||
|
assert(modular_main_called == Py_True || modular_main_called == Py_False);
|
||||||
|
bool val = modular_main_called == Py_True;
|
||||||
|
|
||||||
|
Py_DECREF(baenv);
|
||||||
|
Py_DECREF(env_globals_class);
|
||||||
|
Py_DECREF(get_call);
|
||||||
|
Py_DECREF(env_globals_instance);
|
||||||
|
Py_DECREF(modular_main_called);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CorePython::FetchPythonArgs(std::vector<std::string>* buffer)
|
||||||
|
-> std::vector<char*> {
|
||||||
|
// This gets called in modular builds before anything is inited, so we need to
|
||||||
|
// avoid using anything from g_core or whatnot here; only raw Python stuff.
|
||||||
|
|
||||||
|
assert(buffer && buffer->empty());
|
||||||
|
PyObject* sys = PyImport_ImportModule("sys");
|
||||||
|
if (!sys) {
|
||||||
|
FatalError("Unable to import sys module.");
|
||||||
|
}
|
||||||
|
PyObject* argv = PyObject_GetAttrString(sys, "argv");
|
||||||
|
if (!argv || !PyList_Check(argv)) {
|
||||||
|
FatalError("Unable to fetch sys.argv list.");
|
||||||
|
}
|
||||||
|
Py_ssize_t listlen = PyList_GET_SIZE(argv);
|
||||||
|
for (Py_ssize_t i = 0; i < listlen; ++i) {
|
||||||
|
PyObject* arg = PyList_GET_ITEM(argv, i);
|
||||||
|
BA_PRECONDITION_FATAL(PyUnicode_Check(arg));
|
||||||
|
buffer->push_back(PyUnicode_AsUTF8(arg));
|
||||||
|
}
|
||||||
|
Py_DECREF(sys);
|
||||||
|
Py_DECREF(argv);
|
||||||
|
|
||||||
|
// Ok, we've filled the buffer so it won't be resizing anymore. Now set up
|
||||||
|
// argv pointers to it.
|
||||||
|
std::vector<char*> out;
|
||||||
|
out.reserve(buffer->size());
|
||||||
|
for (int i = 0; i < buffer->size(); ++i) {
|
||||||
|
out.push_back(const_cast<char*>((*buffer)[i].c_str()));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ballistica::core
|
} // namespace ballistica::core
|
||||||
|
|||||||
@ -43,10 +43,6 @@ class CorePython {
|
|||||||
/// pent up ones) to Python.
|
/// pent up ones) to Python.
|
||||||
void EnablePythonLoggingCalls();
|
void EnablePythonLoggingCalls();
|
||||||
|
|
||||||
/// Should be called just before base feature set import; locks in the
|
|
||||||
/// baenv environment and runs some checks.
|
|
||||||
void ApplyBaEnvConfig();
|
|
||||||
|
|
||||||
/// Calls Python logging function (logging.error, logging.warning, etc.)
|
/// Calls Python logging function (logging.error, logging.warning, etc.)
|
||||||
/// Can be called from any thread at any time. If called before Python
|
/// Can be called from any thread at any time. If called before Python
|
||||||
/// logging is available, logs locally using Logging::DisplayLog()
|
/// logging is available, logs locally using Logging::DisplayLog()
|
||||||
@ -56,6 +52,13 @@ class CorePython {
|
|||||||
void VerifyPythonEnvironment();
|
void VerifyPythonEnvironment();
|
||||||
void SoftImportBase();
|
void SoftImportBase();
|
||||||
|
|
||||||
|
static auto WasModularMainCalled() -> bool;
|
||||||
|
|
||||||
|
/// Builds a vector of strings out of Python's sys.argv. Returns an argv
|
||||||
|
/// array pointing to them.
|
||||||
|
static auto FetchPythonArgs(std::vector<std::string>* buffer)
|
||||||
|
-> std::vector<char*>;
|
||||||
|
|
||||||
const auto& objs() { return objs_; }
|
const auto& objs() { return objs_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -75,45 +75,36 @@ static auto ParseArgValue(int argc, char** argv, int* i, const char* arg_long,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CoreConfig::FromCommandLineAndEnv(int argc, char** argv) -> CoreConfig {
|
void CoreConfig::ApplyEnvVars() {
|
||||||
auto cfg = CoreConfig();
|
|
||||||
|
|
||||||
// First set any values we allow env-vars for.
|
|
||||||
// We want explicitly passed values to override these in any cases where both
|
|
||||||
// forms are accepted.
|
|
||||||
if (auto* envval = getenv("BA_LIFECYCLE_LOG")) {
|
if (auto* envval = getenv("BA_LIFECYCLE_LOG")) {
|
||||||
if (!strcmp(envval, "1")) {
|
if (!strcmp(envval, "1")) {
|
||||||
cfg.lifecycle_log = true;
|
lifecycle_log = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (auto* envval = getenv("BA_DEBUGGER_ATTACHED")) {
|
if (auto* envval = getenv("BA_DEBUGGER_ATTACHED")) {
|
||||||
if (!strcmp(envval, "1")) {
|
if (!strcmp(envval, "1")) {
|
||||||
cfg.debugger_attached = true;
|
debugger_attached = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (auto* envval = getenv("BA_DEBUG_TIMING")) {
|
if (auto* envval = getenv("BA_DEBUG_TIMING")) {
|
||||||
if (!strcmp(envval, "1")) {
|
if (!strcmp(envval, "1")) {
|
||||||
cfg.debug_timing = true;
|
debug_timing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// REMOVE ME FOR 1.7.20 FINAL.
|
void CoreConfig::ApplyArgs(int argc, char** argv) {
|
||||||
if (explicit_bool(false)) {
|
|
||||||
printf("TEMP: forcing BA_LIFECYCLE_LOG=1 during 1.7.20 development.\n");
|
|
||||||
cfg.lifecycle_log = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// First handle single-arg special cases like --help or --version.
|
// First handle single-arg special cases like --help or --version.
|
||||||
if (IsSingleArgSpecialCase(argc, argv, "--help", "-h")) {
|
if (IsSingleArgSpecialCase(argc, argv, "--help", "-h")) {
|
||||||
PrintHelp();
|
PrintHelp();
|
||||||
cfg.immediate_return_code = 0;
|
immediate_return_code = 0;
|
||||||
return cfg;
|
return;
|
||||||
}
|
}
|
||||||
if (IsSingleArgSpecialCase(argc, argv, "--version", "-v")) {
|
if (IsSingleArgSpecialCase(argc, argv, "--version", "-v")) {
|
||||||
printf("BallisticaKit %s build %d\n", kEngineVersion, kEngineBuildNumber);
|
printf("BallisticaKit %s build %d\n", kEngineVersion, kEngineBuildNumber);
|
||||||
cfg.immediate_return_code = 0;
|
immediate_return_code = 0;
|
||||||
return cfg;
|
return;
|
||||||
}
|
}
|
||||||
if (IsSingleArgSpecialCase(argc, argv, "--crash")) {
|
if (IsSingleArgSpecialCase(argc, argv, "--crash")) {
|
||||||
int dummyval{};
|
int dummyval{};
|
||||||
@ -126,7 +117,7 @@ auto CoreConfig::FromCommandLineAndEnv(int argc, char** argv) -> CoreConfig {
|
|||||||
if (explicit_bool(true)) {
|
if (explicit_bool(true)) {
|
||||||
*invalid_ptr = 1;
|
*invalid_ptr = 1;
|
||||||
}
|
}
|
||||||
return cfg;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ok, all single-arg cases handled; now go through everything else
|
// Ok, all single-arg cases handled; now go through everything else
|
||||||
@ -135,35 +126,35 @@ auto CoreConfig::FromCommandLineAndEnv(int argc, char** argv) -> CoreConfig {
|
|||||||
std::optional<std::string> value;
|
std::optional<std::string> value;
|
||||||
while (i < argc) {
|
while (i < argc) {
|
||||||
if ((value = ParseArgValue(argc, argv, &i, "--command", "-c"))) {
|
if ((value = ParseArgValue(argc, argv, &i, "--command", "-c"))) {
|
||||||
cfg.call_command = *value;
|
call_command = *value;
|
||||||
} else if ((value = ParseArgValue(argc, argv, &i, "--exec", "-e"))) {
|
} else if ((value = ParseArgValue(argc, argv, &i, "--exec", "-e"))) {
|
||||||
cfg.exec_command = *value;
|
exec_command = *value;
|
||||||
} else if ((value =
|
} else if ((value =
|
||||||
ParseArgValue(argc, argv, &i, "--config-dir", "-C"))) {
|
ParseArgValue(argc, argv, &i, "--config-dir", "-C"))) {
|
||||||
cfg.config_dir = *value;
|
config_dir = *value;
|
||||||
// Make sure what they passed exists.
|
// Make sure what they passed exists.
|
||||||
// Note: Normally baenv will try to create whatever the config dir is;
|
// Note: Normally baenv will try to create whatever the config dir is;
|
||||||
// do we just want to allow that to happen in this case? But perhaps
|
// do we just want to allow that to happen in this case? But perhaps
|
||||||
// being more strict is ok when accepting user input.
|
// being more strict is ok when accepting user input.
|
||||||
if (!std::filesystem::exists(*cfg.config_dir)) {
|
if (!std::filesystem::is_directory(*config_dir)) {
|
||||||
printf("Error: Provided config dir does not exist: '%s'.",
|
printf("Error: Provided config-dir path '%s' is not a directory.",
|
||||||
cfg.config_dir->c_str());
|
config_dir->c_str());
|
||||||
throw BadArgsException();
|
throw BadArgsException();
|
||||||
}
|
}
|
||||||
} else if ((value = ParseArgValue(argc, argv, &i, "--data-dir", "-d"))) {
|
} else if ((value = ParseArgValue(argc, argv, &i, "--data-dir", "-d"))) {
|
||||||
cfg.data_dir = *value;
|
data_dir = *value;
|
||||||
// Make sure what they passed exists.
|
// Make sure what they passed exists.
|
||||||
if (!std::filesystem::exists(*cfg.data_dir)) {
|
if (!std::filesystem::is_directory(*data_dir)) {
|
||||||
printf("Error: Provided data dir does not exist: '%s'.",
|
printf("Error: Provided data-dir path '%s' is not a directory.",
|
||||||
cfg.data_dir->c_str());
|
data_dir->c_str());
|
||||||
throw BadArgsException();
|
throw BadArgsException();
|
||||||
}
|
}
|
||||||
} else if ((value = ParseArgValue(argc, argv, &i, "--mods-dir", "-m"))) {
|
} else if ((value = ParseArgValue(argc, argv, &i, "--mods-dir", "-m"))) {
|
||||||
cfg.user_python_dir = *value;
|
user_python_dir = *value;
|
||||||
// Make sure what they passed exists.
|
// Make sure what they passed exists.
|
||||||
if (!std::filesystem::exists(*cfg.user_python_dir)) {
|
if (!std::filesystem::is_directory(*user_python_dir)) {
|
||||||
printf("Error: Provided mods dir does not exist: '%s'.",
|
printf("Error: Provided mods-dir path '%s' is not a directory.",
|
||||||
cfg.user_python_dir->c_str());
|
user_python_dir->c_str());
|
||||||
throw BadArgsException();
|
throw BadArgsException();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -175,8 +166,25 @@ auto CoreConfig::FromCommandLineAndEnv(int argc, char** argv) -> CoreConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const BadArgsException&) {
|
} catch (const BadArgsException&) {
|
||||||
cfg.immediate_return_code = 1;
|
immediate_return_code = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CoreConfig::ForEnvVars() -> CoreConfig {
|
||||||
|
CoreConfig cfg{};
|
||||||
|
|
||||||
|
cfg.ApplyEnvVars();
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CoreConfig::ForArgsAndEnvVars(int argc, char** argv) -> CoreConfig {
|
||||||
|
CoreConfig cfg{};
|
||||||
|
|
||||||
|
// Apply env-vars first. We want explicit args to override these.
|
||||||
|
cfg.ApplyEnvVars();
|
||||||
|
cfg.ApplyArgs(argc, argv);
|
||||||
|
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,17 @@ namespace ballistica::core {
|
|||||||
/// when initing the core feature-set.
|
/// when initing the core feature-set.
|
||||||
class CoreConfig {
|
class CoreConfig {
|
||||||
public:
|
public:
|
||||||
static auto FromCommandLineAndEnv(int argc, char** argv) -> CoreConfig;
|
static auto ForArgsAndEnvVars(int argc, char** argv) -> CoreConfig;
|
||||||
|
|
||||||
|
static auto ForEnvVars() -> CoreConfig;
|
||||||
|
|
||||||
|
/// Build a core-config for a modular app being run from the command-line.
|
||||||
|
/// In this case, Python has already been inited and Ballistica has
|
||||||
|
/// already been imported (since that's where this code lives) so there is
|
||||||
|
/// less that can be affected by a core-config.
|
||||||
|
|
||||||
|
void ApplyEnvVars();
|
||||||
|
void ApplyArgs(int argc, char** argv);
|
||||||
|
|
||||||
/// Enable vr mode on supported platforms.
|
/// Enable vr mode on supported platforms.
|
||||||
bool vr_mode{};
|
bool vr_mode{};
|
||||||
@ -26,19 +36,19 @@ class CoreConfig {
|
|||||||
std::optional<int> immediate_return_code{};
|
std::optional<int> immediate_return_code{};
|
||||||
|
|
||||||
/// If set, this single Python command will be run instead of the
|
/// If set, this single Python command will be run instead of the
|
||||||
/// normal app loop.
|
/// normal app loop (monolithic builds only).
|
||||||
std::optional<std::string> call_command{};
|
std::optional<std::string> call_command{};
|
||||||
|
|
||||||
/// Python command to be run within the normal app loop.
|
/// Python command to be run within the normal app loop.
|
||||||
std::optional<std::string> exec_command{};
|
std::optional<std::string> exec_command{};
|
||||||
|
|
||||||
/// Explicitly set config dir.
|
/// Explicitly passed config dir.
|
||||||
std::optional<std::string> config_dir{};
|
std::optional<std::string> config_dir{};
|
||||||
|
|
||||||
/// Explicitly set data dir.
|
/// Explicitly passed data dir.
|
||||||
std::optional<std::string> data_dir{};
|
std::optional<std::string> data_dir{};
|
||||||
|
|
||||||
/// Explicitly set user-python (mods) dir.
|
/// Explicitly passed user-python (mods) dir.
|
||||||
std::optional<std::string> user_python_dir{};
|
std::optional<std::string> user_python_dir{};
|
||||||
|
|
||||||
/// Log various stages/times in the bootstrapping process.
|
/// Log various stages/times in the bootstrapping process.
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
#if BA_MONOLITHIC_BUILD && BA_DEFINE_MAIN
|
#if BA_MONOLITHIC_BUILD && BA_DEFINE_MAIN
|
||||||
auto main(int argc, char** argv) -> int {
|
auto main(int argc, char** argv) -> int {
|
||||||
auto core_config =
|
auto core_config =
|
||||||
ballistica::core::CoreConfig::FromCommandLineAndEnv(argc, argv);
|
ballistica::core::CoreConfig::ForArgsAndEnvVars(argc, argv);
|
||||||
|
|
||||||
// Arg-parsing may have yielded an error or printed simple output for
|
// Arg-parsing may have yielded an error or printed simple output for
|
||||||
// things such as '--help', in which case we're done.
|
// things such as '--help', in which case we're done.
|
||||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
|||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|
||||||
// These are set automatically via script; don't modify them here.
|
// These are set automatically via script; don't modify them here.
|
||||||
const int kEngineBuildNumber = 21196;
|
const int kEngineBuildNumber = 21199;
|
||||||
const char* kEngineVersion = "1.7.24";
|
const char* kEngineVersion = "1.7.24";
|
||||||
|
|
||||||
#if BA_MONOLITHIC_BUILD
|
#if BA_MONOLITHIC_BUILD
|
||||||
@ -65,9 +65,6 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
|||||||
// import it first thing even if we don't explicitly use it.
|
// import it first thing even if we don't explicitly use it.
|
||||||
l_core = core::CoreFeatureSet::Import(&core_config);
|
l_core = core::CoreFeatureSet::Import(&core_config);
|
||||||
|
|
||||||
// TEMP - bug hunting.
|
|
||||||
l_core->platform->DebugLog("mm1");
|
|
||||||
|
|
||||||
// If a command was passed, simply run it and exit. We want to act
|
// If a command was passed, simply run it and exit. We want to act
|
||||||
// simply as a Python interpreter in that case; we don't do any
|
// simply as a Python interpreter in that case; we don't do any
|
||||||
// environment setup (aside from the bits core does automatically such
|
// environment setup (aside from the bits core does automatically such
|
||||||
@ -80,9 +77,6 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
|||||||
exit(success ? 0 : 1);
|
exit(success ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEMP - bug hunting.
|
|
||||||
l_core->platform->DebugLog("mm2");
|
|
||||||
|
|
||||||
// Ok, looks like we're doing a standard monolithic-mode app run.
|
// Ok, looks like we're doing a standard monolithic-mode app run.
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
@ -95,9 +89,6 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
|||||||
// those modules get loaded from in the first place.
|
// those modules get loaded from in the first place.
|
||||||
l_core->python->MonolithicModeBaEnvConfigure();
|
l_core->python->MonolithicModeBaEnvConfigure();
|
||||||
|
|
||||||
// TEMP - bug hunting.
|
|
||||||
l_core->platform->DebugLog("mm3");
|
|
||||||
|
|
||||||
// We need the base feature-set to run a full app but we don't have a hard
|
// We need the base feature-set to run a full app but we don't have a hard
|
||||||
// dependency to it. Let's see if it's available.
|
// dependency to it. Let's see if it's available.
|
||||||
l_base = l_core->SoftImportBase();
|
l_base = l_core->SoftImportBase();
|
||||||
@ -109,9 +100,6 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
|||||||
// Phase 2: "The pieces are moving."
|
// Phase 2: "The pieces are moving."
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
// TEMP - bug hunting.
|
|
||||||
l_core->platform->DebugLog("mm4");
|
|
||||||
|
|
||||||
// Spin up all app machinery such as threads and subsystems. This gets
|
// Spin up all app machinery such as threads and subsystems. This gets
|
||||||
// things ready to rock, but there's no actual rocking quite yet.
|
// things ready to rock, but there's no actual rocking quite yet.
|
||||||
l_base->StartApp();
|
l_base->StartApp();
|
||||||
@ -120,9 +108,6 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
|||||||
// Phase 3: "We come to it at last; the great battle of our time."
|
// Phase 3: "We come to it at last; the great battle of our time."
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
// TEMP - bug hunting.
|
|
||||||
l_core->platform->DebugLog("mm5");
|
|
||||||
|
|
||||||
// At this point we unleash the beast and then simply process events
|
// At this point we unleash the beast and then simply process events
|
||||||
// until the app exits (or we return from this function and let the
|
// until the app exits (or we return from this function and let the
|
||||||
// environment do that part).
|
// environment do that part).
|
||||||
@ -165,7 +150,6 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l_core) {
|
if (l_core) {
|
||||||
l_core->platform->WillExitMain(false);
|
l_core->platform->WillExitMain(false);
|
||||||
return l_core->return_value;
|
return l_core->return_value;
|
||||||
|
|||||||
@ -105,7 +105,8 @@ auto Python::GetPyString(PyObject* o) -> std::string {
|
|||||||
return PyUnicode_AsUTF8(o);
|
return PyUnicode_AsUTF8(o);
|
||||||
}
|
}
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Can't get string from value: " + Python::ObjToString(o) + ".", exctype);
|
"Expected a string object; got type " + Python::ObjTypeToString(o) + ".",
|
||||||
|
exctype);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -220,6 +221,24 @@ auto Python::GetPyFloats(PyObject* o) -> std::vector<float> {
|
|||||||
return vals;
|
return vals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Python::GetPyStrings(PyObject* o) -> std::list<std::string> {
|
||||||
|
assert(HaveGIL());
|
||||||
|
BA_PRECONDITION_FATAL(o != nullptr);
|
||||||
|
|
||||||
|
if (!PySequence_Check(o)) {
|
||||||
|
throw Exception("Object is not a sequence.", PyExcType::kType);
|
||||||
|
}
|
||||||
|
PythonRef sequence(PySequence_Fast(o, "Not a sequence."), PythonRef::kSteal);
|
||||||
|
assert(sequence.Exists());
|
||||||
|
Py_ssize_t size = PySequence_Fast_GET_SIZE(sequence.Get());
|
||||||
|
PyObject** py_objects = PySequence_Fast_ITEMS(sequence.Get());
|
||||||
|
std::list<std::string> vals;
|
||||||
|
for (Py_ssize_t i = 0; i < size; i++) {
|
||||||
|
vals.emplace_back(Python::GetPyString(py_objects[i]));
|
||||||
|
}
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto GetPyIntsT(PyObject* o) -> std::vector<T> {
|
auto GetPyIntsT(PyObject* o) -> std::vector<T> {
|
||||||
assert(Python::HaveGIL());
|
assert(Python::HaveGIL());
|
||||||
|
|||||||
@ -121,6 +121,7 @@ class Python {
|
|||||||
static auto GetPyInts(PyObject* o) -> std::vector<int>;
|
static auto GetPyInts(PyObject* o) -> std::vector<int>;
|
||||||
static auto GetPyUInts64(PyObject* o) -> std::vector<uint64_t>;
|
static auto GetPyUInts64(PyObject* o) -> std::vector<uint64_t>;
|
||||||
static auto GetPyPoint2D(PyObject* o) -> Point2D;
|
static auto GetPyPoint2D(PyObject* o) -> Point2D;
|
||||||
|
static auto GetPyStrings(PyObject* o) -> std::list<std::string>;
|
||||||
|
|
||||||
/// Set Python exception from C++ Exception.
|
/// Set Python exception from C++ Exception.
|
||||||
static void SetPythonException(const Exception& exc);
|
static void SetPythonException(const Exception& exc);
|
||||||
|
|||||||
@ -12,14 +12,14 @@ namespace ballistica {
|
|||||||
|
|
||||||
// String based Python commands.
|
// String based Python commands.
|
||||||
|
|
||||||
// Note to self: originally I though I'd be using this in a lot of places,
|
// Note to self: Originally I though I'd be using this in a lot of places,
|
||||||
// so I added the ability to compile once and run repeatedly, quietly capture
|
// so I added the ability to compile once and run repeatedly, quietly
|
||||||
// output instead of printing it, etc. Now, however, its usage is pretty
|
// capture output instead of printing it, etc. Now, however, its usage is
|
||||||
// much limited to a few places such as handling stdin and the in-game console.
|
// pretty much limited to a few places such as handling stdin and the
|
||||||
// (Most places it is much cleaner to work with proper python modules and just
|
// in-app console. (Most places it is much cleaner to work with proper
|
||||||
// interact with PyObject* refs to them)
|
// python modules and just interact with PyObject* refs to them) I should
|
||||||
// I should look and see if python's default high level calls would suffice
|
// look and see if python's default high level calls would suffice for these
|
||||||
// for these purposes and potentially kill this off.
|
// purposes and potentially kill this off.
|
||||||
class PythonCommand {
|
class PythonCommand {
|
||||||
public:
|
public:
|
||||||
PythonCommand();
|
PythonCommand();
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "ballistica/core/python/core_python.h"
|
#include "ballistica/core/python/core_python.h"
|
||||||
#include "ballistica/core/support/base_soft.h"
|
#include "ballistica/core/support/base_soft.h"
|
||||||
|
#include "ballistica/shared/foundation/types.h"
|
||||||
#include "ballistica/shared/math/vector2f.h"
|
#include "ballistica/shared/math/vector2f.h"
|
||||||
#include "ballistica/shared/python/python.h"
|
#include "ballistica/shared/python/python.h"
|
||||||
#include "ballistica/shared/python/python_sys.h"
|
#include "ballistica/shared/python/python_sys.h"
|
||||||
@ -13,7 +14,6 @@ namespace ballistica {
|
|||||||
// Note: implicitly using core globals here; our behavior is undefined
|
// Note: implicitly using core globals here; our behavior is undefined
|
||||||
// if core has not been imported by anyone yet.
|
// if core has not been imported by anyone yet.
|
||||||
using core::g_base_soft;
|
using core::g_base_soft;
|
||||||
using core::g_core;
|
|
||||||
|
|
||||||
// Ignore a few things that python macros do.
|
// Ignore a few things that python macros do.
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
@ -179,6 +179,16 @@ auto PythonRef::ValueAsOptionalString() const -> std::optional<std::string> {
|
|||||||
return Python::GetPyString(obj_);
|
return Python::GetPyString(obj_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto PythonRef::ValueAsOptionalStringSequence() const
|
||||||
|
-> std::optional<std::list<std::string>> {
|
||||||
|
assert(Python::HaveGIL());
|
||||||
|
ThrowIfUnset();
|
||||||
|
if (obj_ == Py_None) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return Python::GetPyStrings(obj_);
|
||||||
|
}
|
||||||
|
|
||||||
auto PythonRef::ValueAsInt() const -> int64_t {
|
auto PythonRef::ValueAsInt() const -> int64_t {
|
||||||
assert(Python::HaveGIL());
|
assert(Python::HaveGIL());
|
||||||
ThrowIfUnset();
|
ThrowIfUnset();
|
||||||
@ -238,15 +248,8 @@ auto PythonRef::UnicodeCheck() const -> bool {
|
|||||||
return static_cast<bool>(PyUnicode_Check(obj_));
|
return static_cast<bool>(PyUnicode_Check(obj_));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PythonRef::Call(PyObject* args, PyObject* keywds, bool print_errors) const
|
static inline auto _HandleCallResults(PyObject* out, bool print_errors)
|
||||||
-> PythonRef {
|
-> PyObject* {
|
||||||
assert(obj_);
|
|
||||||
assert(Python::HaveGIL());
|
|
||||||
assert(CallableCheck());
|
|
||||||
assert(args);
|
|
||||||
assert(PyTuple_Check(args)); // NOLINT (signed bitwise stuff)
|
|
||||||
assert(!keywds || PyDict_Check(keywds)); // NOLINT (signed bitwise)
|
|
||||||
PyObject* out = PyObject_Call(obj_, args, keywds);
|
|
||||||
if (!out) {
|
if (!out) {
|
||||||
if (print_errors) {
|
if (print_errors) {
|
||||||
// Save/restore error or it can mess with context print calls.
|
// Save/restore error or it can mess with context print calls.
|
||||||
@ -262,20 +265,36 @@ auto PythonRef::Call(PyObject* args, PyObject* keywds, bool print_errors) const
|
|||||||
}
|
}
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PythonRef::Call(PyObject* args, PyObject* keywds, bool print_errors) const
|
||||||
|
-> PythonRef {
|
||||||
|
assert(obj_);
|
||||||
|
assert(Python::HaveGIL());
|
||||||
|
assert(CallableCheck());
|
||||||
|
assert(args);
|
||||||
|
assert(PyTuple_Check(args)); // NOLINT (signed bitwise stuff)
|
||||||
|
assert(!keywds || PyDict_Check(keywds)); // NOLINT (signed bitwise)
|
||||||
|
PyObject* out = PyObject_Call(obj_, args, keywds);
|
||||||
|
out = _HandleCallResults(out, print_errors);
|
||||||
return out ? PythonRef(out, PythonRef::kSteal) : PythonRef();
|
return out ? PythonRef(out, PythonRef::kSteal) : PythonRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PythonRef::Call() const -> PythonRef {
|
auto PythonRef::Call(bool print_errors) const -> PythonRef {
|
||||||
// NOTE: Using core globals directly here; normally don't do this.
|
assert(obj_);
|
||||||
assert(g_core);
|
assert(Python::HaveGIL());
|
||||||
return Call(
|
assert(CallableCheck());
|
||||||
g_core->python->objs().Get(core::CorePython::ObjID::kEmptyTuple).Get());
|
PyObject* out = PyObject_CallNoArgs(obj_);
|
||||||
|
out = _HandleCallResults(out, print_errors);
|
||||||
|
return out ? PythonRef(out, PythonRef::kSteal) : PythonRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PythonRef::Call(const Vector2f& val) const -> PythonRef {
|
auto PythonRef::Call(const Vector2f& val, bool print_errors) const
|
||||||
|
-> PythonRef {
|
||||||
assert(Python::HaveGIL());
|
assert(Python::HaveGIL());
|
||||||
PythonRef args(Py_BuildValue("((ff))", val.x, val.y), PythonRef::kSteal);
|
PythonRef args(Py_BuildValue("((ff))", val.x, val.y), PythonRef::kSteal);
|
||||||
return Call(args);
|
return Call(args.Get(), nullptr, print_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
PythonRef::~PythonRef() { Release(); }
|
PythonRef::~PythonRef() { Release(); }
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#ifndef BALLISTICA_SHARED_PYTHON_PYTHON_REF_H_
|
#ifndef BALLISTICA_SHARED_PYTHON_PYTHON_REF_H_
|
||||||
#define BALLISTICA_SHARED_PYTHON_PYTHON_REF_H_
|
#define BALLISTICA_SHARED_PYTHON_PYTHON_REF_H_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -166,6 +167,8 @@ class PythonRef {
|
|||||||
|
|
||||||
auto ValueAsString() const -> std::string;
|
auto ValueAsString() const -> std::string;
|
||||||
auto ValueAsOptionalString() const -> std::optional<std::string>;
|
auto ValueAsOptionalString() const -> std::optional<std::string>;
|
||||||
|
auto ValueAsOptionalStringSequence() const
|
||||||
|
-> std::optional<std::list<std::string>>;
|
||||||
|
|
||||||
auto ValueAsInt() const -> int64_t;
|
auto ValueAsInt() const -> int64_t;
|
||||||
|
|
||||||
@ -185,10 +188,10 @@ class PythonRef {
|
|||||||
bool print_errors = true) const -> PythonRef {
|
bool print_errors = true) const -> PythonRef {
|
||||||
return Call(args.Get(), keywds.Get(), print_errors);
|
return Call(args.Get(), keywds.Get(), print_errors);
|
||||||
}
|
}
|
||||||
auto Call() const -> PythonRef;
|
auto Call(bool print_errors = true) const -> PythonRef;
|
||||||
|
|
||||||
/// Call with Vector2f passed as a tuple.
|
/// Call with Vector2f passed as a tuple.
|
||||||
auto Call(const Vector2f& val) const -> PythonRef;
|
auto Call(const Vector2f& val, bool print_errors = true) const -> PythonRef;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ThrowIfUnset() const;
|
void ThrowIfUnset() const;
|
||||||
|
|||||||
@ -271,6 +271,8 @@ def _writefuncs(
|
|||||||
returnstr = 'return (0.0, 0.0)'
|
returnstr = 'return (0.0, 0.0)'
|
||||||
elif returns == 'str | None':
|
elif returns == 'str | None':
|
||||||
returnstr = "return ''"
|
returnstr = "return ''"
|
||||||
|
elif returns == 'int | None':
|
||||||
|
returnstr = 'return 0'
|
||||||
elif returns == 'tuple[float, float, float, float]':
|
elif returns == 'tuple[float, float, float, float]':
|
||||||
returnstr = 'return (0.0, 0.0, 0.0, 0.0)'
|
returnstr = 'return (0.0, 0.0, 0.0, 0.0)'
|
||||||
elif returns == 'bauiv1.Widget | None':
|
elif returns == 'bauiv1.Widget | None':
|
||||||
|
|||||||
@ -105,7 +105,7 @@ class Pruner:
|
|||||||
self.paths = [os.path.abspath(p) for p in self.paths]
|
self.paths = [os.path.abspath(p) for p in self.paths]
|
||||||
|
|
||||||
def _get_entries(self) -> list[_CompileCommandsEntry]:
|
def _get_entries(self) -> list[_CompileCommandsEntry]:
|
||||||
cmdspath = '.cache/irony/compile_commands.json'
|
cmdspath = '.cache/compile_commands_db/compile_commands.json'
|
||||||
if not os.path.isfile(cmdspath):
|
if not os.path.isfile(cmdspath):
|
||||||
raise CleanError(
|
raise CleanError(
|
||||||
f'Compile-commands not found at "{cmdspath}".'
|
f'Compile-commands not found at "{cmdspath}".'
|
||||||
|
|||||||
@ -786,34 +786,16 @@ class SpinoffContext:
|
|||||||
if 'base' in self._src_omit_feature_sets:
|
if 'base' in self._src_omit_feature_sets:
|
||||||
text = replace_exact(
|
text = replace_exact(
|
||||||
text,
|
text,
|
||||||
(
|
' import babase\n',
|
||||||
'def _main() -> None:\n'
|
' # (Hack; spinoff disabled babase).\n'
|
||||||
' # Run a default configure BEFORE importing'
|
' if TYPE_CHECKING:\n'
|
||||||
' babase.\n'
|
' from typing import Any\n'
|
||||||
' # (may affect where babase comes from).\n'
|
'\n'
|
||||||
' configure()\n'
|
' # import babase\n'
|
||||||
'\n'
|
'\n'
|
||||||
' import babase\n'
|
' babase: Any = None\n'
|
||||||
'\n'
|
' if bool(True):\n'
|
||||||
' babase.app.run()\n'
|
" raise CleanError('babase not present')\n",
|
||||||
'\n'
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'def _main() -> None:\n'
|
|
||||||
' # DISABLED; REQUIRES BASE FEATURE SET.\n'
|
|
||||||
' # Run a default configure BEFORE importing'
|
|
||||||
' babase.\n'
|
|
||||||
' # (may affect where babase comes from).\n'
|
|
||||||
' # configure()\n'
|
|
||||||
'\n'
|
|
||||||
' # import babase\n'
|
|
||||||
'\n'
|
|
||||||
' # babase.app.run()\n'
|
|
||||||
'\n'
|
|
||||||
" raise RuntimeError('App-exec requires"
|
|
||||||
" base feature set.')\n"
|
|
||||||
'\n'
|
|
||||||
),
|
|
||||||
label=src_path,
|
label=src_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1587,7 +1569,7 @@ class SpinoffContext:
|
|||||||
os.chmod(dst_path_full, mode)
|
os.chmod(dst_path_full, mode)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Invalid entity type: '{src_entity['type']}'."
|
f"Invalid entity type: '{src_entity.entity_type}'."
|
||||||
)
|
)
|
||||||
|
|
||||||
# NOTE TO SELF - was using lchmod here but it doesn't exist
|
# NOTE TO SELF - was using lchmod here but it doesn't exist
|
||||||
|
|||||||
@ -526,7 +526,7 @@ class AssetStager:
|
|||||||
'# Basically this will do:\n'
|
'# Basically this will do:\n'
|
||||||
'# import baenv; baenv.configure();'
|
'# import baenv; baenv.configure();'
|
||||||
' import babase; babase.app.run().\n'
|
' import babase; babase.app.run().\n'
|
||||||
'exec python3.11 ba_data/python/baenv.py $@\n'
|
'exec python3.11 ba_data/python/baenv.py "$@"\n'
|
||||||
)
|
)
|
||||||
subprocess.run(['chmod', '+x', path], check=True)
|
subprocess.run(['chmod', '+x', path], check=True)
|
||||||
|
|
||||||
|
|||||||
@ -25,16 +25,18 @@ class CleanError(Exception):
|
|||||||
more descriptive exception types.
|
more descriptive exception types.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def pretty_print(self, flush: bool = False) -> None:
|
def pretty_print(self, flush: bool = True, prefix: str = 'Error') -> None:
|
||||||
"""Print the error to stdout, using red colored output if available.
|
"""Print the error to stdout, using red colored output if available.
|
||||||
|
|
||||||
If the error has an empty message, prints nothing (not even a newline).
|
If the error has an empty message, prints nothing (not even a newline).
|
||||||
"""
|
"""
|
||||||
from efro.terminal import Clr
|
from efro.terminal import Clr
|
||||||
|
|
||||||
|
if prefix:
|
||||||
|
prefix = f'{prefix}: '
|
||||||
errstr = str(self)
|
errstr = str(self)
|
||||||
if errstr:
|
if errstr:
|
||||||
print(f'{Clr.SRED}{errstr}{Clr.RST}', flush=flush)
|
print(f'{Clr.SRED}{prefix}{errstr}{Clr.RST}', flush=flush)
|
||||||
|
|
||||||
|
|
||||||
class CommunicationError(Exception):
|
class CommunicationError(Exception):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user