mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 13:25:31 +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/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/data/langdata.json": "https://files.ballistica.net/cache/ba1/b8/5e/c8766634397fb77ae3a407c05d63",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/6f/38/958616d8cb85916aa8b2bcd84f63",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/57/68/d03a19b9035cfae7cdc5377d889a",
|
||||
"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/db/96/1f7fe0541a31880929e1c17ea957",
|
||||
"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/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",
|
||||
@ -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/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/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/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/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/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/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/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/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/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/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/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/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/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",
|
||||
@ -4068,50 +4068,50 @@
|
||||
"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/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/release/ballisticakit": "https://files.ballistica.net/cache/ba1/50/dd/86cbb96aca3a339318b00574b2db",
|
||||
"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/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/93/04/19410cb96b5c12fc2cd20dd9c099",
|
||||
"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/release/ballisticakit": "https://files.ballistica.net/cache/ba1/16/68/6011835e4db7927b26761847950b",
|
||||
"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/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/8a/76/54da9b7ff4d79164d3f4dea2782b",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/4a/08/bf75de3244efe6fc342139a6da32",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/33/c7/d3534c1d605b5bcc4a541457cde9",
|
||||
"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/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/f5/be/f80777972954ebe6fd91b52a6533",
|
||||
"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/release/ballisticakit": "https://files.ballistica.net/cache/ba1/23/46/72f453ea380bd5f04957886c2b57",
|
||||
"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/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/b5/e6/451f3cc73b5b79d21b19c2416d61",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/b2/0e/778420dfd1a6f81ed457a94f8f1d",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/00/76/0f4dd3bbf7a98f00221307535b4f",
|
||||
"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/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/82/99/e0a873f37e95674f2151ea99bf3d",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/b3/a2/5da0c4dc65f469e4a476e0395eb5",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/a9/9a/adb83188f9c7d7b51dafd0f8b8a8",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/b3/a2/5da0c4dc65f469e4a476e0395eb5",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/a9/9a/adb83188f9c7d7b51dafd0f8b8a8",
|
||||
"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/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/7b/f3/f98278c9654a972baf65d5f04c12",
|
||||
"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/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/7b/f3/f98278c9654a972baf65d5f04c12",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/c7/a2/40728a3ebfb3006c7a47b698214f",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/84/19/a1bbbf42c50329f0cd1377d103bb",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/c7/a2/40728a3ebfb3006c7a47b698214f",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/84/19/a1bbbf42c50329f0cd1377d103bb",
|
||||
"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/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/59/fe/a3e369f2db87a305641e74ae70ab",
|
||||
"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/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/59/fe/a3e369f2db87a305641e74ae70ab",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/91/2f/362a643d543963de549d830fe604",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/2e/d4/67d6c0f9b372eb5cd92c9def6fc8",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/68/8b/d6049425f1069d256abdaf90004c",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/3e/82/f70e75696765ac05875cb5dd778c",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/38/ee/56658557aa2ecabd0d30eb01b68e",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/6b/4c/568766d02bbca174752488850737",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/3e/5b/1aa2252706188de69075eb7b3656",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/ab/a7/21bc5acc8a823bd7c7ec940e97bc",
|
||||
"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/3f/fe/4c9f0926b60c6a4f5253fde8bb35",
|
||||
"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/37/ba/ee706254c5a21f08b8d4c47bb6e2",
|
||||
"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/11/f3/0feed20f5d34c23d96b39e5702ae",
|
||||
"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/bc/b1/66680fead22bdecfcd4c8d825f8b",
|
||||
"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/ef/1c/ddcdbedb47affd72d2f4c5164fd9",
|
||||
"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/c1/ed/4691901b692a59e598bd982f6d5b",
|
||||
"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/fa/8c/79e39ee8297c9946f3dfed5d47c4",
|
||||
"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/2a/c3/4378d0290b122a345787b46ef23c",
|
||||
"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/c2/4b/04f9d9a58fa1d1cefc096cf84e57",
|
||||
"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/65/8f/25f37b8f6175fbe9274576e2eb4a",
|
||||
"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/9d/2b/44367bfb114e7b1148e4e100acd1",
|
||||
"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/9d/2b/44367bfb114e7b1148e4e100acd1",
|
||||
"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/a3/38/2c4abbc88434720311048185fdd1",
|
||||
"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/a3/38/2c4abbc88434720311048185fdd1",
|
||||
"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/75/af/1ca3bec27e72101585254739189d",
|
||||
"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/75/af/1ca3bec27e72101585254739189d",
|
||||
"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/06/ab/699f575fabf3819dcf40b4c3125e",
|
||||
"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/06/ab/699f575fabf3819dcf40b4c3125e",
|
||||
"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/b0/55/536be0beef09a49ecca957ca7318",
|
||||
"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/bd/f3/6f99da945c68fae7f860e69f86c6",
|
||||
"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/1e/fa/09a99039de3bf810e3ed13959416",
|
||||
"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/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/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",
|
||||
|
||||
4
.idea/dictionaries/ericf.xml
generated
4
.idea/dictionaries/ericf.xml
generated
@ -125,6 +125,7 @@
|
||||
<w>appletvsimulator</w>
|
||||
<w>appmode</w>
|
||||
<w>appmodeselector</w>
|
||||
<w>appmodule</w>
|
||||
<w>appname</w>
|
||||
<w>appnameupper</w>
|
||||
<w>appnow</w>
|
||||
@ -904,6 +905,7 @@
|
||||
<w>enumvalue</w>
|
||||
<w>enval</w>
|
||||
<w>envcfg</w>
|
||||
<w>envconfig</w>
|
||||
<w>envglobals</w>
|
||||
<w>envhash</w>
|
||||
<w>envname</w>
|
||||
@ -1892,6 +1894,7 @@
|
||||
<w>namedarg</w>
|
||||
<w>namel</w>
|
||||
<w>namepre</w>
|
||||
<w>namepretty</w>
|
||||
<w>nametext</w>
|
||||
<w>nameu</w>
|
||||
<w>nameval</w>
|
||||
@ -2432,6 +2435,7 @@
|
||||
<w>redist</w>
|
||||
<w>redistributables</w>
|
||||
<w>reenabled</w>
|
||||
<w>reexpose</w>
|
||||
<w>regionid</w>
|
||||
<w>registerexecutionpolicyexception</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="float.__getitem__" />
|
||||
<option value="pbxproj.pbxsections.PBXGroup.PBXGroup.children" />
|
||||
<option value="bascenev1lib.game.race.Player.__getitem__" />
|
||||
<option value="batools.project._updater._LineChange.__getitem__" />
|
||||
</list>
|
||||
</option>
|
||||
</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
|
||||
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
|
||||
|
||||
48
Makefile
48
Makefile
@ -28,11 +28,11 @@
|
||||
help:
|
||||
@tools/pcommand makefile_target_list Makefile
|
||||
|
||||
# Set env-var BA_ENABLE_IRONY_BUILD_DB=1 to enable creating/updating a cmake
|
||||
# compile-commands database for use with irony for emacs (and possibly other
|
||||
# tools).
|
||||
ifeq ($(BA_ENABLE_IRONY_BUILD_DB),1)
|
||||
PREREQ_IRONY_BUILD_DB = .cache/irony/compile_commands.json
|
||||
# Set env-var BA_ENABLE_COMPILE_COMMANDS_DB=1 to enable creating/updating a
|
||||
# cmake compile-commands database for use with irony for emacs (and possibly
|
||||
# other tools).
|
||||
ifeq ($(BA_ENABLE_COMPILE_COMMANDS_DB),1)
|
||||
PREREQ_COMPILE_COMMANDS_DB = .cache/compile_commands_db/compile_commands.json
|
||||
endif
|
||||
|
||||
# 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
|
||||
# included in PREREQS_SAFE it would try to build *before* project updates
|
||||
# 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.
|
||||
# This installs tool config files, runs environment checks, etc.
|
||||
@ -1010,20 +1010,20 @@ CMAKE_BUILD_TYPE ?= Debug
|
||||
|
||||
# Build and run the 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.
|
||||
# Sets up the ballistica environment to do things like abort() out to the
|
||||
# debugger on errors instead of trying to cleanly exit.
|
||||
cmake-gdb: cmake-build
|
||||
@cd build/cmake/$(CM_BT_LC)/staged && \
|
||||
cd build/cmake/$(CM_BT_LC)/staged && \
|
||||
BA_DEBUGGER_ATTACHED=1 gdb ./ballisticakit
|
||||
|
||||
# Build and run the cmake build under the lldb debugger.
|
||||
# Sets up the ballistica environment to do things like abort() out to the
|
||||
# debugger on errors instead of trying to cleanly exit.
|
||||
cmake-lldb: cmake-build
|
||||
@cd build/cmake/$(CM_BT_LC)/staged && \
|
||||
cd build/cmake/$(CM_BT_LC)/staged && \
|
||||
BA_DEBUGGER_ATTACHED=1 lldb ./ballisticakit
|
||||
|
||||
# Build but don't run it.
|
||||
@ -1045,7 +1045,7 @@ cmake-clean:
|
||||
rm -rf build/cmake/$(CM_BT_LC)
|
||||
|
||||
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
|
||||
@$(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
|
||||
|
||||
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
|
||||
@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)
|
||||
|
||||
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
|
||||
@$(STAGE_BUILD) -cmakemodularserver -$(CM_BT_LC) \
|
||||
@ -1221,21 +1221,21 @@ ballisticakit-cmake/.clang-format: .clang-format
|
||||
@mkdir -p ballisticakit-cmake
|
||||
@cd ballisticakit-cmake && ln -sf ../.clang-format .
|
||||
|
||||
# Irony in emacs requires us to use cmake to generate a full
|
||||
# list of compile commands for all files; lets try to keep it up to date
|
||||
# Various tools such as Irony for Emacs or clangd make use of a list of
|
||||
# compile commands for all files; lets try to keep it up to date
|
||||
# whenever CMakeLists changes.
|
||||
.cache/irony/compile_commands.json: ballisticakit-cmake/CMakeLists.txt
|
||||
@tools/pcommand echo BLU Updating Irony build commands db...
|
||||
@echo Generating Irony compile-commands-list...
|
||||
@mkdir -p .cache/irony
|
||||
@cd .cache/irony \
|
||||
.cache/compile_commands_db/compile_commands.json: \
|
||||
ballisticakit-cmake/CMakeLists.txt
|
||||
@tools/pcommand echo BLU Updating compile commands db...
|
||||
@mkdir -p .cache/compile_commands_db
|
||||
@cd .cache/compile_commands_db \
|
||||
&& cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug \
|
||||
$(shell pwd)/ballisticakit-cmake
|
||||
@mv .cache/irony/compile_commands.json . \
|
||||
&& rm -rf .cache/irony \
|
||||
&& mkdir .cache/irony \
|
||||
&& mv compile_commands.json .cache/irony
|
||||
@tools/pcommand echo BLU Created Irony build db at $@
|
||||
@mv .cache/compile_commands_db/compile_commands.json . \
|
||||
&& rm -rf .cache/compile_commands_db \
|
||||
&& mkdir .cache/compile_commands_db \
|
||||
&& mv compile_commands.json .cache/compile_commands_db
|
||||
@tools/pcommand echo BLU Created compile commands db at $@
|
||||
|
||||
_windows-wsl-build:
|
||||
@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>appmode</w>
|
||||
<w>appmodeselector</w>
|
||||
<w>appmodule</w>
|
||||
<w>appname</w>
|
||||
<w>appnameupper</w>
|
||||
<w>appnow</w>
|
||||
@ -549,6 +550,7 @@
|
||||
<w>enumvalue</w>
|
||||
<w>enval</w>
|
||||
<w>envcfg</w>
|
||||
<w>envconfig</w>
|
||||
<w>envglobals</w>
|
||||
<w>envs</w>
|
||||
<w>envval</w>
|
||||
@ -1102,6 +1104,7 @@
|
||||
<w>namecap</w>
|
||||
<w>namel</w>
|
||||
<w>namepre</w>
|
||||
<w>namepretty</w>
|
||||
<w>nameu</w>
|
||||
<w>nameval</w>
|
||||
<w>nbuffer</w>
|
||||
@ -1430,6 +1433,7 @@
|
||||
<w>recvfrom</w>
|
||||
<w>redundants</w>
|
||||
<w>reenabled</w>
|
||||
<w>reexpose</w>
|
||||
<w>refcounted</w>
|
||||
<w>refl</w>
|
||||
<w>regionid</w>
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
;;; 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.
|
||||
((c++-mode (eval . (flycheck-mode)))
|
||||
(
|
||||
;; (c++-mode (eval . (flycheck-mode)))
|
||||
|
||||
|
||||
(python-ts-mode (jedi:server-args . ("--sys-path" "__EFRO_PROJECT_ROOT__/tools"
|
||||
@ -22,8 +23,18 @@
|
||||
(nil . ((projectile-globally-ignored-directories . ("docs"
|
||||
"submodules"
|
||||
"src/external"
|
||||
"src/assets/ba_data/python-site-packages"
|
||||
"src/assets/pylib-android"
|
||||
"src/assets/pylib-apple"
|
||||
"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,
|
||||
fatal_error,
|
||||
get_display_resolution,
|
||||
get_immediate_return_code,
|
||||
get_low_level_config_value,
|
||||
get_max_graphics_quality,
|
||||
get_replays_dir,
|
||||
@ -204,6 +205,7 @@ __all__ = [
|
||||
'fatal_error',
|
||||
'garbage_collect',
|
||||
'get_display_resolution',
|
||||
'get_immediate_return_code',
|
||||
'get_ip_address_type',
|
||||
'get_low_level_config_value',
|
||||
'get_max_graphics_quality',
|
||||
|
||||
@ -156,11 +156,11 @@ def on_app_launching() -> None:
|
||||
|
||||
assert _babase.in_logic_thread()
|
||||
|
||||
# Let the user know if the app Python dir is a custom one.
|
||||
user_sys_scripts_dir = baenv.get_user_system_scripts_dir()
|
||||
if user_sys_scripts_dir is not None:
|
||||
# Let the user know if the app Python dir is a 'user' one.
|
||||
envconfig = baenv.get_config()
|
||||
if envconfig.is_user_app_python_dir:
|
||||
_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),
|
||||
)
|
||||
|
||||
|
||||
@ -24,20 +24,19 @@ from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
import __main__
|
||||
|
||||
from efro.log import setup_logging, LogLevel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from efro.log import LogHandler
|
||||
|
||||
# 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
|
||||
# the job of this module to set up paths for an engine run, and that may
|
||||
# involve modifying sys.path in such a way that this module resolves to
|
||||
# a different path afterwards (for example from
|
||||
# the job of this module to set up Python paths for an engine run, and
|
||||
# that may involve modifying sys.path in such a way that this module
|
||||
# resolves to a different path afterwards (for example from
|
||||
# /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'
|
||||
# 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.
|
||||
#
|
||||
@ -51,13 +50,13 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21196
|
||||
TARGET_BALLISTICA_BUILD = 21199
|
||||
TARGET_BALLISTICA_VERSION = '1.7.24'
|
||||
|
||||
|
||||
@dataclass
|
||||
class EnvConfig:
|
||||
"""Environment put together by the configure call."""
|
||||
"""Environment values put together by the configure call."""
|
||||
|
||||
config_dir: str
|
||||
data_dir: str
|
||||
@ -66,49 +65,45 @@ class EnvConfig:
|
||||
standard_app_python_dir: str
|
||||
site_python_dir: str | None
|
||||
log_handler: LogHandler | None
|
||||
is_user_app_python_dir: bool
|
||||
|
||||
|
||||
@dataclass
|
||||
class EnvGlobals:
|
||||
class _EnvGlobals:
|
||||
"""Our globals we store in the main module."""
|
||||
|
||||
config: EnvConfig | None = None
|
||||
config_called: bool = False
|
||||
called_configure: bool = False
|
||||
paths_set_failed: bool = False
|
||||
user_system_scripts_dir: str | None = None
|
||||
modular_main_called: bool = False
|
||||
|
||||
@classmethod
|
||||
def get(cls) -> EnvGlobals:
|
||||
def get(cls) -> _EnvGlobals:
|
||||
"""Create/return our singleton."""
|
||||
name = '_baenv_globals'
|
||||
envglobals: EnvGlobals | None = getattr(__main__, name, None)
|
||||
envglobals: _EnvGlobals | None = getattr(__main__, name, None)
|
||||
if envglobals is None:
|
||||
envglobals = EnvGlobals()
|
||||
envglobals = _EnvGlobals()
|
||||
setattr(__main__, name, 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:
|
||||
"""Has a config been created?"""
|
||||
|
||||
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
|
||||
return _EnvGlobals.get().config is not None
|
||||
|
||||
|
||||
def get_config() -> EnvConfig:
|
||||
"""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()
|
||||
|
||||
config = envglobals.config
|
||||
@ -128,7 +123,7 @@ def configure(
|
||||
site_python_dir: str | None = None,
|
||||
contains_python_dist: bool = False,
|
||||
) -> 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
|
||||
creation. This should be called before any other ballistica modules
|
||||
@ -136,14 +131,14 @@ def configure(
|
||||
where those modules get loaded from.
|
||||
"""
|
||||
|
||||
envglobals = EnvGlobals.get()
|
||||
envglobals = _EnvGlobals.get()
|
||||
|
||||
if envglobals.config_called:
|
||||
if envglobals.called_configure:
|
||||
raise RuntimeError(
|
||||
'baenv.configure() has already been called;'
|
||||
' 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
|
||||
# Python's stdout/stderr into it. Then we can at least debug
|
||||
@ -167,6 +162,7 @@ def configure(
|
||||
data_dir,
|
||||
config_dir,
|
||||
standard_app_python_dir,
|
||||
is_user_app_python_dir,
|
||||
) = _setup_paths(
|
||||
user_python_dir,
|
||||
app_python_dir,
|
||||
@ -190,6 +186,7 @@ def configure(
|
||||
standard_app_python_dir=standard_app_python_dir,
|
||||
site_python_dir=site_python_dir,
|
||||
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:
|
||||
from efro.log import setup_logging, LogLevel
|
||||
|
||||
log_handler = setup_logging(
|
||||
log_path=None,
|
||||
level=LogLevel.DEBUG,
|
||||
@ -249,11 +248,11 @@ def _setup_paths(
|
||||
site_python_dir: str | None,
|
||||
data_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
|
||||
# Python imports:
|
||||
|
||||
envglobals = EnvGlobals.get()
|
||||
envglobals = _EnvGlobals.get()
|
||||
|
||||
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 = 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
|
||||
# at this point aside from complain and inform for next time.
|
||||
if '_babase' in sys.modules:
|
||||
@ -299,7 +301,8 @@ def _setup_paths(
|
||||
# stuff.
|
||||
check_dir = Path(user_python_dir, 'sys', TARGET_BALLISTICA_VERSION)
|
||||
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.
|
||||
|
||||
@ -342,6 +345,7 @@ def _setup_paths(
|
||||
data_dir,
|
||||
config_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:
|
||||
# Run a default configure BEFORE importing babase.
|
||||
# (may affect where babase comes from).
|
||||
configure()
|
||||
def extract_arg(args: list[str], names: list[str], is_dir: bool) -> str | None:
|
||||
"""Given a list of args and an arg name, returns a value.
|
||||
|
||||
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__':
|
||||
_main()
|
||||
_modular_main()
|
||||
|
||||
@ -45,6 +45,7 @@ from babase import (
|
||||
NodeNotFoundError,
|
||||
normalized_color,
|
||||
NotFoundError,
|
||||
PlayerNotFoundError,
|
||||
Plugin,
|
||||
pushcall,
|
||||
safecolor,
|
||||
@ -374,6 +375,7 @@ __all__ = [
|
||||
'PlayerDiedMessage',
|
||||
'PlayerProfilesChangedMessage',
|
||||
'PlayerInfo',
|
||||
'PlayerNotFoundError',
|
||||
'PlayerRecord',
|
||||
'PlayerScoredMessage',
|
||||
'Plugin',
|
||||
|
||||
@ -4,14 +4,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class CoopJoinActivity(bs.JoinActivity):
|
||||
"""Join-screen for co-op mode."""
|
||||
@ -46,7 +40,7 @@ class CoopJoinActivity(bs.JoinActivity):
|
||||
).autoretain()
|
||||
ControlsGuide(delay=1.0).autoretain()
|
||||
|
||||
babase.pushcall(self._show_remaining_achievements)
|
||||
bs.pushcall(self._show_remaining_achievements)
|
||||
|
||||
def _show_remaining_achievements(self) -> None:
|
||||
from bascenev1lib.actor.text import Text
|
||||
@ -70,22 +64,22 @@ class CoopJoinActivity(bs.JoinActivity):
|
||||
ts_h_offs = 60
|
||||
|
||||
# Show remaining achievements in some cases.
|
||||
if babase.app.classic is not None and not (
|
||||
babase.app.demo_mode or babase.app.arcade_mode
|
||||
if bs.app.classic is not None and not (
|
||||
bs.app.demo_mode or bs.app.arcade_mode
|
||||
):
|
||||
achievements = [
|
||||
a
|
||||
for a in babase.app.classic.ach.achievements_for_coop_level(
|
||||
for a in bs.app.classic.ach.achievements_for_coop_level(
|
||||
levelname
|
||||
)
|
||||
if not a.complete
|
||||
]
|
||||
have_achievements = bool(achievements)
|
||||
achievements = [a for a in achievements if not a.complete]
|
||||
vrmode = babase.app.vr_mode
|
||||
vrmode = bs.app.vr_mode
|
||||
if have_achievements:
|
||||
Text(
|
||||
babase.Lstr(resource='achievementsRemainingText'),
|
||||
bs.Lstr(resource='achievementsRemainingText'),
|
||||
host_only=True,
|
||||
position=(ts_h_offs - 10, vpos),
|
||||
transition=Text.Transition.FADE_IN,
|
||||
@ -105,7 +99,7 @@ class CoopJoinActivity(bs.JoinActivity):
|
||||
vpos -= 55
|
||||
if not achievements:
|
||||
Text(
|
||||
babase.Lstr(resource='noAchievementsRemainingText'),
|
||||
bs.Lstr(resource='noAchievementsRemainingText'),
|
||||
host_only=True,
|
||||
position=(ts_h_offs + 15, vpos + 10),
|
||||
transition=Text.Transition.FADE_IN,
|
||||
|
||||
@ -4,15 +4,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||
from bascenev1lib.actor.zoomtext import ZoomText
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class DrawScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
@ -21,10 +15,10 @@ class DrawScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
default_music = None # Awkward silence...
|
||||
|
||||
def on_begin(self) -> None:
|
||||
babase.set_analytics_screen('Draw Score Screen')
|
||||
bs.set_analytics_screen('Draw Score Screen')
|
||||
super().on_begin()
|
||||
ZoomText(
|
||||
babase.Lstr(resource='drawText'),
|
||||
bs.Lstr(resource='drawText'),
|
||||
position=(0, 0),
|
||||
maxwidth=400,
|
||||
shiftposition=(-220, 0),
|
||||
|
||||
@ -4,16 +4,10 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||
from bascenev1lib.actor.zoomtext import ZoomText
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
"""Scorescreen between rounds of a dual-team session."""
|
||||
@ -24,7 +18,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
assert isinstance(self._winner, bs.SessionTeam)
|
||||
|
||||
def on_begin(self) -> None:
|
||||
babase.set_analytics_screen('Teams Score Screen')
|
||||
bs.set_analytics_screen('Teams Score Screen')
|
||||
super().on_begin()
|
||||
|
||||
height = 130
|
||||
@ -37,13 +31,13 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
# 'First to 4'.
|
||||
session = self.session
|
||||
assert isinstance(session, bs.MultiTeamSession)
|
||||
if babase.app.lang.get_resource('bestOfUseFirstToInstead'):
|
||||
best_txt = babase.Lstr(
|
||||
if bs.app.lang.get_resource('bestOfUseFirstToInstead'):
|
||||
best_txt = bs.Lstr(
|
||||
resource='firstToSeriesText',
|
||||
subs=[('${COUNT}', str(session.get_series_length() / 2 + 1))],
|
||||
)
|
||||
else:
|
||||
best_txt = babase.Lstr(
|
||||
best_txt = bs.Lstr(
|
||||
resource='bestOfSeriesText',
|
||||
subs=[('${COUNT}', str(session.get_series_length()))],
|
||||
)
|
||||
@ -63,7 +57,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
for team in self.session.sessionteams:
|
||||
bs.timer(
|
||||
i * 0.15 + 0.15,
|
||||
babase.WeakCall(
|
||||
bs.WeakCall(
|
||||
self._show_team_name,
|
||||
vval - i * height,
|
||||
team,
|
||||
@ -78,7 +72,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
delay = 1.2
|
||||
bs.timer(
|
||||
i * 0.150 + 0.2,
|
||||
babase.WeakCall(
|
||||
bs.WeakCall(
|
||||
self._show_team_old_score,
|
||||
vval - i * height,
|
||||
team,
|
||||
@ -89,7 +83,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
|
||||
bs.timer(
|
||||
i * 0.150 + delay,
|
||||
babase.WeakCall(
|
||||
bs.WeakCall(
|
||||
self._show_team_score,
|
||||
vval - i * height,
|
||||
team,
|
||||
@ -110,7 +104,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
) -> None:
|
||||
del kill_delay # Unused arg.
|
||||
ZoomText(
|
||||
babase.Lstr(value='${A}:', subs=[('${A}', team.name)]),
|
||||
bs.Lstr(value='${A}:', subs=[('${A}', team.name)]),
|
||||
position=(100, pos_v),
|
||||
shiftposition=(-150, pos_v),
|
||||
shiftdelay=shiftdelay,
|
||||
|
||||
@ -4,15 +4,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
from bascenev1lib.actor.text import Text
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class MultiTeamJoinActivity(bs.JoinActivity):
|
||||
"""Join screen for teams sessions."""
|
||||
@ -32,10 +26,10 @@ class MultiTeamJoinActivity(bs.JoinActivity):
|
||||
|
||||
# Show info about the next up game.
|
||||
self._next_up_text = Text(
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
value='${1} ${2}',
|
||||
subs=[
|
||||
('${1}', babase.Lstr(resource='upFirstText')),
|
||||
('${1}', bs.Lstr(resource='upFirstText')),
|
||||
('${2}', session.get_next_game_description()),
|
||||
],
|
||||
),
|
||||
@ -72,12 +66,12 @@ class MultiTeamJoinActivity(bs.JoinActivity):
|
||||
).autoretain()
|
||||
|
||||
Text(
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
resource='mustInviteFriendsText',
|
||||
subs=[
|
||||
(
|
||||
'${GATHER}',
|
||||
babase.Lstr(resource='gatherWindow.titleText'),
|
||||
bs.Lstr(resource='gatherWindow.titleText'),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
@ -3,16 +3,10 @@
|
||||
"""Functionality related to teams mode score screen."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
from bascenev1lib.actor.text import Text
|
||||
from bascenev1lib.actor.image import Image
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
"""Base class for score screens."""
|
||||
@ -28,12 +22,12 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
super().on_begin()
|
||||
session = self.session
|
||||
if self._show_up_next and isinstance(session, bs.MultiTeamSession):
|
||||
txt = babase.Lstr(
|
||||
txt = bs.Lstr(
|
||||
value='${A} ${B}',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
resource='upNextText',
|
||||
subs=[
|
||||
('${COUNT}', str(session.get_game_number() + 1))
|
||||
@ -84,7 +78,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
return val
|
||||
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:
|
||||
assert isinstance(results, bs.GameResults)
|
||||
assert p_rec.team.activityteam is not None
|
||||
@ -135,7 +129,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
def _txt(
|
||||
xoffs: float,
|
||||
yoffs: float,
|
||||
text: babase.Lstr,
|
||||
text: bs.Lstr,
|
||||
h_align: Text.HAlign = Text.HAlign.RIGHT,
|
||||
extrascale: float = 1.0,
|
||||
maxwidth: float | None = 120.0,
|
||||
@ -157,7 +151,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
|
||||
session = self.session
|
||||
assert isinstance(session, bs.MultiTeamSession)
|
||||
tval = babase.Lstr(
|
||||
tval = bs.Lstr(
|
||||
resource='gameLeadersText',
|
||||
subs=[('${COUNT}', str(session.get_game_number()))],
|
||||
)
|
||||
@ -169,14 +163,12 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
extrascale=1.4,
|
||||
maxwidth=None,
|
||||
)
|
||||
_txt(
|
||||
-15, 4, babase.Lstr(resource='playerText'), h_align=Text.HAlign.LEFT
|
||||
)
|
||||
_txt(180, 4, babase.Lstr(resource='killsText'))
|
||||
_txt(280, 4, babase.Lstr(resource='deathsText'), maxwidth=100)
|
||||
_txt(-15, 4, bs.Lstr(resource='playerText'), h_align=Text.HAlign.LEFT)
|
||||
_txt(180, 4, bs.Lstr(resource='killsText'))
|
||||
_txt(280, 4, bs.Lstr(resource='deathsText'), maxwidth=100)
|
||||
|
||||
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)
|
||||
|
||||
@ -191,7 +183,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
topkilledcount = min(topkilledcount, prec.accum_killed_count)
|
||||
|
||||
def _scoretxt(
|
||||
text: str | babase.Lstr,
|
||||
text: str | bs.Lstr,
|
||||
x_offs: float,
|
||||
highlight: bool,
|
||||
delay2: float,
|
||||
@ -228,7 +220,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
transition_delay=tdelay,
|
||||
).autoretain()
|
||||
Text(
|
||||
babase.Lstr(value=playerrec.getname(full=True)),
|
||||
bs.Lstr(value=playerrec.getname(full=True)),
|
||||
maxwidth=160,
|
||||
scale=0.75 * scale,
|
||||
position=(
|
||||
@ -237,7 +229,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
|
||||
),
|
||||
h_align=Text.HAlign.LEFT,
|
||||
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_delay=tdelay,
|
||||
).autoretain()
|
||||
|
||||
@ -4,15 +4,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
"""Final score screen for a team series."""
|
||||
@ -35,25 +29,25 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
from bascenev1lib.actor.text import Text
|
||||
from bascenev1lib.actor.image import Image
|
||||
|
||||
babase.set_analytics_screen(
|
||||
bs.set_analytics_screen(
|
||||
'FreeForAll Series Victory Screen'
|
||||
if self._is_ffa
|
||||
else 'Teams Series Victory Screen'
|
||||
)
|
||||
assert babase.app.classic is not None
|
||||
if babase.app.ui_v1.uiscale is babase.UIScale.LARGE:
|
||||
sval = babase.Lstr(resource='pressAnyKeyButtonPlayAgainText')
|
||||
assert bs.app.classic is not None
|
||||
if bs.app.ui_v1.uiscale is bs.UIScale.LARGE:
|
||||
sval = bs.Lstr(resource='pressAnyKeyButtonPlayAgainText')
|
||||
else:
|
||||
sval = babase.Lstr(resource='pressAnyButtonPlayAgainText')
|
||||
sval = bs.Lstr(resource='pressAnyButtonPlayAgainText')
|
||||
self._show_up_next = False
|
||||
self._custom_continue_message = sval
|
||||
super().on_begin()
|
||||
winning_sessionteam = self.settings_raw['winner']
|
||||
|
||||
# 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(
|
||||
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)
|
||||
|
||||
@ -82,19 +76,19 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
tval = 6.4
|
||||
t_incr = 0.12
|
||||
|
||||
always_use_first_to = babase.app.lang.get_resource(
|
||||
always_use_first_to = bs.app.lang.get_resource(
|
||||
'bestOfUseFirstToInstead'
|
||||
)
|
||||
|
||||
session = self.session
|
||||
if self._is_ffa:
|
||||
assert isinstance(session, bs.FreeForAllSession)
|
||||
txt = babase.Lstr(
|
||||
txt = bs.Lstr(
|
||||
value='${A}:',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
resource='firstToFinalText',
|
||||
subs=[
|
||||
(
|
||||
@ -115,12 +109,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
# they're not using this language. Should try to come up
|
||||
# with a wording that works everywhere.
|
||||
if always_use_first_to:
|
||||
txt = babase.Lstr(
|
||||
txt = bs.Lstr(
|
||||
value='${A}:',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
resource='firstToFinalText',
|
||||
subs=[
|
||||
(
|
||||
@ -135,12 +129,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
],
|
||||
)
|
||||
else:
|
||||
txt = babase.Lstr(
|
||||
txt = bs.Lstr(
|
||||
value='${A}:',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
resource='bestOfFinalText',
|
||||
subs=[
|
||||
(
|
||||
@ -173,7 +167,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
|
||||
if not self._is_ffa:
|
||||
Text(
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
resource='gamesToText',
|
||||
subs=[
|
||||
('${WINCOUNT}', str(win_score)),
|
||||
@ -208,7 +202,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
break
|
||||
if mvp is not None:
|
||||
Text(
|
||||
babase.Lstr(resource='mostValuablePlayerText'),
|
||||
bs.Lstr(resource='mostValuablePlayerText'),
|
||||
color=(0.5, 0.5, 0.5, 1.0),
|
||||
v_align=Text.VAlign.CENTER,
|
||||
maxwidth=300,
|
||||
@ -228,13 +222,13 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
).autoretain()
|
||||
assert mvp_name is not None
|
||||
Text(
|
||||
babase.Lstr(value=mvp_name),
|
||||
bs.Lstr(value=mvp_name),
|
||||
position=(280, ts_height / 2 - 55 + 15 - 5),
|
||||
h_align=Text.HAlign.LEFT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
maxwidth=170,
|
||||
scale=1.3,
|
||||
color=babase.safecolor(mvp.team.color + (1,)),
|
||||
color=bs.safecolor(mvp.team.color + (1,)),
|
||||
transition=Text.Transition.IN_LEFT,
|
||||
transition_delay=tval,
|
||||
).autoretain()
|
||||
@ -249,7 +243,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
most_kills = entry[2].kill_count
|
||||
if mvp is not None:
|
||||
Text(
|
||||
babase.Lstr(resource='mostViolentPlayerText'),
|
||||
bs.Lstr(resource='mostViolentPlayerText'),
|
||||
color=(0.5, 0.5, 0.5, 1.0),
|
||||
v_align=Text.VAlign.CENTER,
|
||||
maxwidth=300,
|
||||
@ -259,12 +253,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
transition_delay=tval,
|
||||
).autoretain()
|
||||
Text(
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
value='(${A})',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
resource='killsTallyText',
|
||||
subs=[('${COUNT}', str(most_kills))],
|
||||
),
|
||||
@ -289,12 +283,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
).autoretain()
|
||||
assert mvp_name is not None
|
||||
Text(
|
||||
babase.Lstr(value=mvp_name),
|
||||
bs.Lstr(value=mvp_name),
|
||||
position=(270, ts_height / 2 - 150 - 30 - 36 + v_extra + 15),
|
||||
h_align=Text.HAlign.LEFT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
maxwidth=180,
|
||||
color=babase.safecolor(mvp.team.color + (1,)),
|
||||
color=bs.safecolor(mvp.team.color + (1,)),
|
||||
transition=Text.Transition.IN_LEFT,
|
||||
transition_delay=tval,
|
||||
).autoretain()
|
||||
@ -310,7 +304,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
most_killed = entry[2].killed_count
|
||||
if mkp is not None:
|
||||
Text(
|
||||
babase.Lstr(resource='mostViolatedPlayerText'),
|
||||
bs.Lstr(resource='mostViolatedPlayerText'),
|
||||
color=(0.5, 0.5, 0.5, 1.0),
|
||||
v_align=Text.VAlign.CENTER,
|
||||
maxwidth=300,
|
||||
@ -320,12 +314,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
transition_delay=tval,
|
||||
).autoretain()
|
||||
Text(
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
value='(${A})',
|
||||
subs=[
|
||||
(
|
||||
'${A}',
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
resource='deathsTallyText',
|
||||
subs=[('${COUNT}', str(most_killed))],
|
||||
),
|
||||
@ -349,11 +343,11 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
).autoretain()
|
||||
assert mkp_name is not None
|
||||
Text(
|
||||
babase.Lstr(value=mkp_name),
|
||||
bs.Lstr(value=mkp_name),
|
||||
position=(270, ts_height / 2 - 300 - 30 - 36 + v_extra + 15),
|
||||
h_align=Text.HAlign.LEFT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
color=babase.safecolor(mkp.team.color + (1,)),
|
||||
color=bs.safecolor(mkp.team.color + (1,)),
|
||||
maxwidth=180,
|
||||
transition=Text.Transition.IN_LEFT,
|
||||
transition_delay=tval,
|
||||
@ -363,7 +357,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
# Now show individual scores.
|
||||
tdelay = tval
|
||||
Text(
|
||||
babase.Lstr(resource='finalScoresText'),
|
||||
bs.Lstr(resource='finalScoresText'),
|
||||
color=(0.5, 0.5, 0.5, 1.0),
|
||||
position=(ts_h_offs, ts_height / 2),
|
||||
transition=Text.Transition.IN_RIGHT,
|
||||
@ -396,17 +390,17 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
transition_delay=tdelay,
|
||||
).autoretain()
|
||||
Text(
|
||||
babase.Lstr(value=name),
|
||||
bs.Lstr(value=name),
|
||||
position=(ts_h_offs - 50, ts_height / 2 + v_offs + 15),
|
||||
h_align=Text.HAlign.LEFT,
|
||||
v_align=Text.VAlign.CENTER,
|
||||
maxwidth=180,
|
||||
color=babase.safecolor(prec.team.color + (1,)),
|
||||
color=bs.safecolor(prec.team.color + (1,)),
|
||||
transition=Text.Transition.IN_RIGHT,
|
||||
transition_delay=tdelay,
|
||||
).autoretain()
|
||||
|
||||
bs.timer(15.0, babase.WeakCall(self._show_tips))
|
||||
bs.timer(15.0, bs.WeakCall(self._show_tips))
|
||||
|
||||
def _show_tips(self) -> None:
|
||||
from bascenev1lib.actor.tipstext import TipsText
|
||||
@ -443,7 +437,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
assert i.node
|
||||
bs.animate(i.node, 'opacity', {0.0: 0.0, 0.25: 1.0})
|
||||
ZoomText(
|
||||
babase.Lstr(
|
||||
bs.Lstr(
|
||||
value=team.players[0].getname(full=True, icon=False)
|
||||
),
|
||||
position=(0, 97 + offs_v),
|
||||
@ -460,7 +454,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
wins_resource = 'seriesWinLine1PlayerText'
|
||||
else:
|
||||
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
|
||||
# unified old form which is more likely to be translated.
|
||||
@ -473,7 +467,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
|
||||
maxwidth=250,
|
||||
).autoretain()
|
||||
ZoomText(
|
||||
babase.Lstr(resource='seriesWinLine2Text'),
|
||||
bs.Lstr(resource='seriesWinLine2Text'),
|
||||
position=(0, -110 + offs_v),
|
||||
scale=1.0 * s_extra,
|
||||
color=team.color,
|
||||
|
||||
@ -6,7 +6,6 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, TypeVar, overload
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
from bascenev1lib.actor.spaz import Spaz
|
||||
|
||||
@ -99,7 +98,7 @@ class PlayerSpaz(Spaz):
|
||||
player: Any = self._player
|
||||
assert isinstance(player, playertype)
|
||||
if not player.exists() and doraise:
|
||||
raise babase.PlayerNotFoundError()
|
||||
raise bs.PlayerNotFoundError()
|
||||
return player if player.exists() else None
|
||||
|
||||
def connect_controls_to_player(
|
||||
@ -129,16 +128,16 @@ class PlayerSpaz(Spaz):
|
||||
else:
|
||||
player.resetinput()
|
||||
|
||||
player.assigninput(babase.InputType.UP_DOWN, self.on_move_up_down)
|
||||
player.assigninput(babase.InputType.LEFT_RIGHT, self.on_move_left_right)
|
||||
player.assigninput(bs.InputType.UP_DOWN, self.on_move_up_down)
|
||||
player.assigninput(bs.InputType.LEFT_RIGHT, self.on_move_left_right)
|
||||
player.assigninput(
|
||||
babase.InputType.HOLD_POSITION_PRESS, self.on_hold_position_press
|
||||
bs.InputType.HOLD_POSITION_PRESS, self.on_hold_position_press
|
||||
)
|
||||
player.assigninput(
|
||||
babase.InputType.HOLD_POSITION_RELEASE,
|
||||
bs.InputType.HOLD_POSITION_RELEASE,
|
||||
self.on_hold_position_release,
|
||||
)
|
||||
intp = babase.InputType
|
||||
intp = bs.InputType
|
||||
if enable_jump:
|
||||
player.assigninput(intp.JUMP_PRESS, self.on_jump_press)
|
||||
player.assigninput(intp.JUMP_RELEASE, self.on_jump_release)
|
||||
@ -210,7 +209,7 @@ class PlayerSpaz(Spaz):
|
||||
picked_up_by = msg.node.source_player
|
||||
if 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')
|
||||
elif isinstance(msg, bs.StandMessage):
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
@ -248,7 +247,7 @@ class PlayerSpaz(Spaz):
|
||||
# something like last_actor_attacked_by to fix that.
|
||||
if (
|
||||
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
|
||||
else:
|
||||
@ -279,7 +278,7 @@ class PlayerSpaz(Spaz):
|
||||
source_player = msg.get_source_player(type(self._player))
|
||||
if 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)
|
||||
super().handlemessage(msg) # Augment standard behavior.
|
||||
activity = self._activity()
|
||||
|
||||
@ -7,7 +7,6 @@ from __future__ import annotations
|
||||
import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -22,7 +21,7 @@ class PopupText(bs.Actor):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
text: str | babase.Lstr,
|
||||
text: str | bs.Lstr,
|
||||
position: Sequence[float] = (0.0, 0.0, 0.0),
|
||||
color: Sequence[float] = (1.0, 1.0, 1.0, 1.0),
|
||||
random_offset: float = 0.5,
|
||||
@ -116,7 +115,7 @@ class PopupText(bs.Actor):
|
||||
|
||||
# kill ourself
|
||||
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:
|
||||
|
||||
@ -5,14 +5,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import weakref
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class RespawnIcon:
|
||||
"""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.
|
||||
"""
|
||||
|
||||
_MASKTEXSTORENAME = babase.storagename('masktex')
|
||||
_ICONSSTORENAME = babase.storagename('icons')
|
||||
_MASKTEXSTORENAME = bs.storagename('masktex')
|
||||
_ICONSSTORENAME = bs.storagename('icons')
|
||||
|
||||
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
|
||||
|
||||
on_right, offs_extra, respawn_icons = self._get_context(player)
|
||||
@ -81,13 +76,13 @@ class RespawnIcon:
|
||||
attrs={
|
||||
'v_attach': 'top',
|
||||
'h_attach': 'right' if on_right else 'left',
|
||||
'text': babase.Lstr(value=player.getname()),
|
||||
'text': bs.Lstr(value=player.getname()),
|
||||
'maxwidth': 100,
|
||||
'h_align': 'center',
|
||||
'v_align': 'center',
|
||||
'shadow': 1.0,
|
||||
'flatness': 1.0,
|
||||
'color': babase.safecolor(icon['tint_color']),
|
||||
'color': bs.safecolor(icon['tint_color']),
|
||||
'scale': 0.5,
|
||||
'position': npos,
|
||||
},
|
||||
@ -109,7 +104,7 @@ class RespawnIcon:
|
||||
'shadow': 0.5,
|
||||
'flatness': 0.5,
|
||||
'v_attach': 'top',
|
||||
'color': babase.safecolor(icon['tint_color']),
|
||||
'color': bs.safecolor(icon['tint_color']),
|
||||
'text': '',
|
||||
},
|
||||
)
|
||||
@ -118,10 +113,10 @@ class RespawnIcon:
|
||||
assert self._text.node
|
||||
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._timer: bs.Timer | None = bs.Timer(
|
||||
1.0, babase.WeakCall(self._update), repeat=True
|
||||
1.0, bs.WeakCall(self._update), repeat=True
|
||||
)
|
||||
|
||||
@property
|
||||
@ -159,7 +154,7 @@ class RespawnIcon:
|
||||
return on_right, offs_extra, icons
|
||||
|
||||
def _update(self) -> None:
|
||||
remaining = int(round(self._respawn_time - babase.apptime()))
|
||||
remaining = int(round(self._respawn_time - bs.time()))
|
||||
if remaining > 0:
|
||||
assert self._text is not None
|
||||
if self._text.node:
|
||||
|
||||
@ -7,7 +7,6 @@ from __future__ import annotations
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -56,7 +55,7 @@ class Text(bs.Actor):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
text: str | babase.Lstr,
|
||||
text: str | bs.Lstr,
|
||||
position: tuple[float, float] = (0.0, 0.0),
|
||||
h_align: HAlign = HAlign.LEFT,
|
||||
v_align: VAlign = VAlign.NONE,
|
||||
@ -219,7 +218,7 @@ class Text(bs.Actor):
|
||||
if transition_out_delay is not None:
|
||||
bs.timer(
|
||||
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:
|
||||
|
||||
@ -6,7 +6,6 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -34,8 +33,8 @@ class TipsText(bs.Actor):
|
||||
'v_attach': 'bottom',
|
||||
},
|
||||
)
|
||||
tval = babase.Lstr(
|
||||
value='${A}:', subs=[('${A}', babase.Lstr(resource='tipText'))]
|
||||
tval = bs.Lstr(
|
||||
value='${A}:', subs=[('${A}', bs.Lstr(resource='tipText'))]
|
||||
)
|
||||
self.title_node = bs.newnode(
|
||||
'text',
|
||||
@ -54,7 +53,7 @@ class TipsText(bs.Actor):
|
||||
self._message_spacing = 3000
|
||||
self._change_timer = bs.Timer(
|
||||
0.001 * (self._message_duration + self._message_spacing),
|
||||
babase.WeakCall(self.change_phrase),
|
||||
bs.WeakCall(self.change_phrase),
|
||||
repeat=True,
|
||||
)
|
||||
self._combine = bs.newnode(
|
||||
@ -70,11 +69,11 @@ class TipsText(bs.Actor):
|
||||
"""Switch the visible tip phrase."""
|
||||
from babase import get_remote_app_name
|
||||
|
||||
next_tip = babase.Lstr(
|
||||
next_tip = bs.Lstr(
|
||||
translate=(
|
||||
'tips',
|
||||
babase.app.classic.get_next_tip()
|
||||
if babase.app.classic is not None
|
||||
bs.app.classic.get_next_tip()
|
||||
if bs.app.classic is not None
|
||||
else '',
|
||||
),
|
||||
subs=[('${REMOTE_APP_NAME}', get_remote_app_name())],
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -24,7 +24,7 @@ class ZoomText(bs.Actor):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
text: str | babase.Lstr,
|
||||
text: str | bs.Lstr,
|
||||
position: tuple[float, float] = (0.0, 0.0),
|
||||
shiftposition: tuple[float, float] | None = None,
|
||||
shiftdelay: float | None = None,
|
||||
@ -47,7 +47,7 @@ class ZoomText(bs.Actor):
|
||||
if shiftdelay is None:
|
||||
shiftdelay = 2.500
|
||||
if shiftdelay < 0.0:
|
||||
babase.print_error('got shiftdelay < 0')
|
||||
logging.error('got shiftdelay < 0')
|
||||
shiftdelay = 0.0
|
||||
self._project_scale = project_scale
|
||||
self.node = bs.newnode(
|
||||
@ -69,7 +69,7 @@ class ZoomText(bs.Actor):
|
||||
)
|
||||
|
||||
# we never jitter in vr mode..
|
||||
if babase.app.vr_mode:
|
||||
if bs.app.vr_mode:
|
||||
jitter = 0.0
|
||||
|
||||
# if they want jitter, animate its position slightly...
|
||||
@ -82,14 +82,12 @@ class ZoomText(bs.Actor):
|
||||
positionadjusted2 = (shiftposition[0], shiftposition[1] - 100)
|
||||
bs.timer(
|
||||
shiftdelay,
|
||||
babase.WeakCall(
|
||||
self._shift, positionadjusted, positionadjusted2
|
||||
),
|
||||
bs.WeakCall(self._shift, positionadjusted, positionadjusted2),
|
||||
)
|
||||
if jitter > 0.0:
|
||||
bs.timer(
|
||||
shiftdelay + 0.25,
|
||||
babase.WeakCall(
|
||||
bs.WeakCall(
|
||||
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 lifespan is not None:
|
||||
bs.timer(
|
||||
lifespan, babase.WeakCall(self.handlemessage, bs.DieMessage())
|
||||
)
|
||||
bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))
|
||||
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
assert not self.expired
|
||||
|
||||
@ -6,7 +6,6 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -23,7 +22,7 @@ class SharedObjects:
|
||||
standard materials.
|
||||
"""
|
||||
|
||||
_STORENAME = babase.storagename()
|
||||
_STORENAME = bs.storagename()
|
||||
|
||||
def __init__(self) -> None:
|
||||
activity = bs.getactivity()
|
||||
|
||||
@ -4,14 +4,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
# FIXME: Could change this to be a classmethod of session types?
|
||||
class PlaylistTypeVars:
|
||||
@ -26,26 +20,26 @@ class PlaylistTypeVars:
|
||||
self.sessiontype: type[bs.Session]
|
||||
|
||||
if issubclass(sessiontype, bs.DualTeamSession):
|
||||
play_mode_name = babase.Lstr(
|
||||
play_mode_name = bs.Lstr(
|
||||
resource='playModes.teamsText', fallback_resource='teamsText'
|
||||
)
|
||||
self.get_default_list_call = get_default_teams_playlist
|
||||
self.session_type_name = 'bascenev1.DualTeamSession'
|
||||
self.config_name = 'Team Tournament'
|
||||
self.window_title_name = babase.Lstr(
|
||||
self.window_title_name = bs.Lstr(
|
||||
resource='playModes.teamsText', fallback_resource='teamsText'
|
||||
)
|
||||
self.sessiontype = bs.DualTeamSession
|
||||
|
||||
elif issubclass(sessiontype, bs.FreeForAllSession):
|
||||
play_mode_name = babase.Lstr(
|
||||
play_mode_name = bs.Lstr(
|
||||
resource='playModes.freeForAllText',
|
||||
fallback_resource='freeForAllText',
|
||||
)
|
||||
self.get_default_list_call = get_default_free_for_all_playlist
|
||||
self.session_type_name = 'bascenev1.FreeForAllSession'
|
||||
self.config_name = 'Free-for-All'
|
||||
self.window_title_name = babase.Lstr(
|
||||
self.window_title_name = bs.Lstr(
|
||||
resource='playModes.freeForAllText',
|
||||
fallback_resource='freeForAllText',
|
||||
)
|
||||
@ -55,11 +49,11 @@ class PlaylistTypeVars:
|
||||
raise RuntimeError(
|
||||
f'Playlist type vars undefined for sessiontype: {sessiontype}'
|
||||
)
|
||||
self.default_list_name = babase.Lstr(
|
||||
self.default_list_name = bs.Lstr(
|
||||
resource='defaultGameListNameText',
|
||||
subs=[('${PLAYMODE}', play_mode_name)],
|
||||
)
|
||||
self.default_new_list_name = babase.Lstr(
|
||||
self.default_new_list_name = bs.Lstr(
|
||||
resource='defaultNewGameListNameText',
|
||||
subs=[('${PLAYMODE}', play_mode_name)],
|
||||
)
|
||||
|
||||
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
import bauiv1 as bui
|
||||
from bauiv1lib.settings.testing import TestingWindow
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -18,10 +18,10 @@ class VRTestingWindow(TestingWindow):
|
||||
|
||||
def __init__(self, transition: str = 'in_right'):
|
||||
entries: list[dict[str, Any]] = []
|
||||
app = babase.app
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
|
||||
# these are gear-vr only
|
||||
# These are gear-vr only.
|
||||
if (
|
||||
app.classic.platform == 'android'
|
||||
and app.classic.subplatform == 'oculus'
|
||||
@ -44,16 +44,19 @@ class VRTestingWindow(TestingWindow):
|
||||
},
|
||||
# {'name':'eyeOffsX','label':'Eye IPD','increment':0.001}
|
||||
]
|
||||
# cardboard/gearvr get eye offset controls..
|
||||
|
||||
# Cardboard/gearvr get eye offset controls.
|
||||
# if app.platform == 'android':
|
||||
# entries += [
|
||||
# {'name':'eyeOffsY','label':'Eye Offset Y','increment':0.01},
|
||||
# {'name':'eyeOffsZ','label':'Eye Offset Z','increment':0.005}]
|
||||
# everyone gets head-scale
|
||||
|
||||
# Everyone gets head-scale.
|
||||
entries += [
|
||||
{'name': 'headScale', 'label': 'Head Scale', 'increment': 1.0}
|
||||
]
|
||||
# and everyone gets all these..
|
||||
|
||||
# And everyone gets all these.
|
||||
entries += [
|
||||
{
|
||||
'name': 'vrCamOffsetY',
|
||||
@ -88,7 +91,7 @@ class VRTestingWindow(TestingWindow):
|
||||
]
|
||||
|
||||
super().__init__(
|
||||
babase.Lstr(resource='settingsWindowAdvanced.vrTestingText'),
|
||||
bui.Lstr(resource='settingsWindowAdvanced.vrTestingText'),
|
||||
entries,
|
||||
transition,
|
||||
)
|
||||
|
||||
@ -7,7 +7,6 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, TypeVar, Generic
|
||||
|
||||
import babase
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -35,7 +34,7 @@ class TabRow(Generic[T]):
|
||||
def __init__(
|
||||
self,
|
||||
parent: bui.Widget,
|
||||
tabdefs: list[tuple[T, babase.Lstr]],
|
||||
tabdefs: list[tuple[T, bui.Lstr]],
|
||||
pos: tuple[float, float],
|
||||
size: tuple[float, float],
|
||||
on_select_call: Callable[[T], None] | None = None,
|
||||
@ -58,7 +57,7 @@ class TabRow(Generic[T]):
|
||||
size=size,
|
||||
label=tab_label,
|
||||
enable_sound=False,
|
||||
on_activate_call=babase.Call(
|
||||
on_activate_call=bui.Call(
|
||||
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 (stress_test_stats_file_ == nullptr) {
|
||||
assert(g_core);
|
||||
auto user_python_dir = g_core->platform->GetUserPythonDirectory();
|
||||
auto user_python_dir = g_core->GetUserPythonDirectory();
|
||||
if (user_python_dir) {
|
||||
std::string f_name = *user_python_dir + "/stress_test_stats.csv";
|
||||
stress_test_stats_file_ =
|
||||
|
||||
@ -39,7 +39,7 @@ static const bool kShowPruningInfo = false;
|
||||
#define PENDING_LOAD_PROCESS_TIME 5
|
||||
|
||||
Assets::Assets() {
|
||||
asset_paths_.emplace_back(g_core->platform->GetDataDirectory() + BA_DIRSLASH
|
||||
asset_paths_.emplace_back(g_core->GetDataDirectory() + BA_DIRSLASH
|
||||
+ "ba_data");
|
||||
for (bool& have_pending_load : have_pending_loads_) {
|
||||
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
|
||||
// BaseFeatureSet. This locks in baenv customizations.
|
||||
g_core->python->ApplyBaEnvConfig();
|
||||
g_core->ApplyBaEnvConfig();
|
||||
|
||||
// Create our feature-set's C++ front-end.
|
||||
assert(g_base == nullptr);
|
||||
|
||||
@ -826,8 +826,8 @@ void TextGraphics::LoadGlyphPage(uint32_t index) {
|
||||
if (g_glyph_pages[index] == nullptr) {
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "%s%sba_data%sfonts%sfontSmall%d.fdata",
|
||||
g_core->platform->GetDataDirectory().c_str(), BA_DIRSLASH,
|
||||
BA_DIRSLASH, BA_DIRSLASH, index);
|
||||
g_core->GetDataDirectory().c_str(), BA_DIRSLASH, BA_DIRSLASH,
|
||||
BA_DIRSLASH, index);
|
||||
FILE* f = g_core->platform->FOpen(buffer, "rb");
|
||||
BA_PRECONDITION(f);
|
||||
BA_PRECONDITION(sizeof(TextGraphics::Glyph[2]) == sizeof(float[18]));
|
||||
|
||||
@ -711,12 +711,9 @@ static auto PyEnv(PyObject* self) -> PyObject* {
|
||||
default:
|
||||
throw Exception();
|
||||
}
|
||||
std::optional<std::string> user_py_dir =
|
||||
g_core->platform->GetUserPythonDirectory();
|
||||
std::optional<std::string> app_py_dir =
|
||||
g_core->platform->GetAppPythonDirectory();
|
||||
std::optional<std::string> site_py_dir =
|
||||
g_core->platform->GetSitePythonDirectory();
|
||||
std::optional<std::string> user_py_dir = g_core->GetUserPythonDirectory();
|
||||
std::optional<std::string> app_py_dir = g_core->GetAppPythonDirectory();
|
||||
std::optional<std::string> site_py_dir = g_core->GetSitePythonDirectory();
|
||||
|
||||
// clang-format off
|
||||
PyObject* env = Py_BuildValue(
|
||||
@ -772,7 +769,7 @@ static auto PyEnv(PyObject* self) -> PyObject* {
|
||||
"device_name",
|
||||
g_core->platform->GetDeviceName().c_str(),
|
||||
"data_directory",
|
||||
g_core->platform->GetDataDirectory().c_str());
|
||||
g_core->GetDataDirectory().c_str());
|
||||
// clang-format on
|
||||
g_base->python->StoreEnv(env);
|
||||
}
|
||||
@ -1449,6 +1446,29 @@ static PyMethodDef PyEmptyAppModeHandleIntentExecDef = {
|
||||
"(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> {
|
||||
@ -1496,6 +1516,7 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
|
||||
PyEmptyAppModeDeactivateDef,
|
||||
PyEmptyAppModeHandleIntentDefaultDef,
|
||||
PyEmptyAppModeHandleIntentExecDef,
|
||||
PyGetImmediateReturnCodeDef,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -854,7 +854,7 @@ static PyMethodDef PySetPlatformMiscReadValsDef = {
|
||||
|
||||
static auto PyGetLogFilePath(PyObject* self, PyObject* args) -> PyObject* {
|
||||
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";
|
||||
return PyUnicode_FromString(logpath.c_str());
|
||||
BA_PYTHON_CATCH;
|
||||
|
||||
@ -15,21 +15,46 @@ CoreFeatureSet* g_core{};
|
||||
BaseSoftInterface* g_base_soft{};
|
||||
|
||||
auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
|
||||
// Only accept a config in monolithic builds if this is the first import.
|
||||
if (config != nullptr) {
|
||||
if (!g_buildconfig.monolithic_build()) {
|
||||
FatalError("CoreConfig can only be passed in monolithic builds.");
|
||||
}
|
||||
if (g_core != nullptr) {
|
||||
FatalError("CoreConfig can only be passed on the first import call.");
|
||||
}
|
||||
|
||||
if (g_core == nullptr) {
|
||||
DoImport(*config);
|
||||
// In monolithic builds we can accept an explicit core-config the first
|
||||
// time we're imported.
|
||||
if (g_buildconfig.monolithic_build()) {
|
||||
if (config != nullptr) {
|
||||
if (g_core != nullptr) {
|
||||
FatalError(
|
||||
"CoreConfig can only be passed on the first CoreFeatureSet::Import "
|
||||
"call.");
|
||||
}
|
||||
if (g_core == nullptr) {
|
||||
DoImport(*config);
|
||||
}
|
||||
} else {
|
||||
// No config passed; use a default.
|
||||
if (g_core == nullptr) {
|
||||
DoImport({});
|
||||
}
|
||||
}
|
||||
} 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) {
|
||||
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;
|
||||
@ -90,14 +115,88 @@ void CoreFeatureSet::PostInit() {
|
||||
// (so that our log handling system is fully bootstrapped), but
|
||||
// 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.
|
||||
if (!g_core->core_config().hold_early_logs) {
|
||||
if (!core_config_.hold_early_logs) {
|
||||
python->EnablePythonLoggingCalls();
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: MOVE THIS TO A RUN_APP_TO_COMPLETION() SORT OF PLACE.
|
||||
// For now it does the right thing here since all we have is monolithic
|
||||
// builds but this will need to account for more situations later.
|
||||
// python->ReleaseMainThreadGIL();
|
||||
auto CoreFeatureSet::core_config() const -> const CoreConfig& {
|
||||
// Try to make a bit of noise if we're accessed in modular builds before
|
||||
// baenv values are set, since in that case we won't yet have our final
|
||||
// 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 {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#ifndef BALLISTICA_CORE_CORE_H_
|
||||
#define BALLISTICA_CORE_CORE_H_
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@ -54,13 +55,15 @@ class CoreFeatureSet {
|
||||
auto SoftImportBase() -> BaseSoftInterface*;
|
||||
|
||||
/// 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.
|
||||
/// Can be used during shutdown or when trying to send a crash-report to
|
||||
/// ensure we don't hang indefinitely.
|
||||
void StartSuicideTimer(const std::string& action, millisecs_t delay);
|
||||
|
||||
void ApplyBaEnvConfig();
|
||||
|
||||
// Call this if the main thread changes.
|
||||
// Fixme: Should come up with something less hacky feeling.
|
||||
void UpdateMainThreadID();
|
||||
@ -108,6 +111,38 @@ class CoreFeatureSet {
|
||||
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.
|
||||
CorePython* const python;
|
||||
CorePlatform* const platform;
|
||||
@ -159,6 +194,13 @@ class CoreFeatureSet {
|
||||
std::mutex app_time_mutex_;
|
||||
std::string legacy_user_agent_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
|
||||
|
||||
@ -144,7 +144,7 @@ auto CorePlatform::GetLegacyDeviceUUID() -> const std::string& {
|
||||
// in our config dir. This should be globally-unique, but the downside is
|
||||
// the user can tamper with it.
|
||||
if (!have_real_unique_uuid) {
|
||||
std::string path = GetConfigDirectory() + BA_DIRSLASH + ".bsuuid";
|
||||
std::string path = g_core->GetConfigDirectory() + BA_DIRSLASH + ".bsuuid";
|
||||
|
||||
if (FILE* f = FOpen(path.c_str(), "rb")) {
|
||||
// There's an existing one; read it.
|
||||
@ -201,13 +201,14 @@ auto CorePlatform::DoGetConfigDirectoryMonolithicDefault()
|
||||
}
|
||||
|
||||
auto CorePlatform::GetConfigFilePath() -> std::string {
|
||||
return GetConfigDirectory() + BA_DIRSLASH + "config.json";
|
||||
return g_core->GetConfigDirectory() + BA_DIRSLASH + "config.json";
|
||||
}
|
||||
|
||||
// FIXME: should make this unnecessary.
|
||||
auto CorePlatform::GetLowLevelConfigValue(const char* key, int default_value)
|
||||
-> int {
|
||||
std::string path = GetConfigDirectory() + BA_DIRSLASH + ".cvar_" + key;
|
||||
std::string path =
|
||||
g_core->GetConfigDirectory() + BA_DIRSLASH + ".cvar_" + key;
|
||||
int val = default_value;
|
||||
FILE* f = FOpen(path.c_str(), "r");
|
||||
if (f) {
|
||||
@ -225,7 +226,8 @@ auto CorePlatform::GetLowLevelConfigValue(const char* key, int default_value)
|
||||
|
||||
// FIXME: should make this unnecessary.
|
||||
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);
|
||||
FILE* f = FOpen(path.c_str(), "w");
|
||||
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 {
|
||||
if (!made_volatile_data_dir_) {
|
||||
volatile_data_dir_ = GetDefaultVolatileDataDirectory();
|
||||
@ -254,23 +251,13 @@ auto CorePlatform::GetVolatileDataDirectory() -> std::string {
|
||||
|
||||
auto CorePlatform::GetDefaultVolatileDataDirectory() -> std::string {
|
||||
// By default, stuff this in a subdir under our config dir.
|
||||
return 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_;
|
||||
return g_core->GetConfigDirectory() + BA_DIRSLASH + "vdata";
|
||||
}
|
||||
|
||||
auto CorePlatform::GetReplaysDir() -> std::string {
|
||||
static bool made_dir = false;
|
||||
if (!made_dir) {
|
||||
replays_dir_ = GetConfigDirectory() + BA_DIRSLASH + "replays";
|
||||
replays_dir_ = g_core->GetConfigDirectory() + BA_DIRSLASH + "replays";
|
||||
MakeDir(replays_dir_);
|
||||
made_dir = true;
|
||||
}
|
||||
@ -355,13 +342,6 @@ auto CorePlatform::GetErrnoString() -> std::string {
|
||||
#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()
|
||||
-> std::optional<std::string> {
|
||||
// CoreConfig value trumps all. Otherwise go with platform-specific default.
|
||||
@ -371,11 +351,6 @@ auto CorePlatform::GetConfigDirectoryMonolithicDefault()
|
||||
return DoGetConfigDirectoryMonolithicDefault();
|
||||
}
|
||||
|
||||
auto CorePlatform::GetDataDirectory() -> std::string {
|
||||
BA_PRECONDITION(have_ba_env_vals_);
|
||||
return ba_env_data_dir_;
|
||||
}
|
||||
|
||||
auto CorePlatform::GetDataDirectoryMonolithicDefault() -> std::string {
|
||||
// CoreConfig arg trumps all. Otherwise ask for platform-specific value.
|
||||
if (g_core->core_config().data_dir.has_value()) {
|
||||
@ -1216,32 +1191,4 @@ auto CorePlatform::System(const char* cmd) -> int {
|
||||
#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
|
||||
|
||||
@ -141,35 +141,16 @@ class CorePlatform {
|
||||
/// etc).
|
||||
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.
|
||||
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>;
|
||||
|
||||
/// Get the path of the app config file.
|
||||
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>;
|
||||
|
||||
/// 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
|
||||
/// directory should not be included in backups and the app should remain
|
||||
/// 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;
|
||||
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?).
|
||||
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:
|
||||
/// Are we being run from a terminal? (should we show prompts, etc?).
|
||||
virtual auto GetIsStdinATerminal() -> bool;
|
||||
@ -544,7 +514,6 @@ class CorePlatform {
|
||||
|
||||
private:
|
||||
bool is_stdin_a_terminal_{};
|
||||
bool using_custom_app_python_dir_{};
|
||||
bool have_has_touchscreen_value_{};
|
||||
bool have_touchscreen_{};
|
||||
bool is_tegra_k1_{};
|
||||
@ -553,17 +522,11 @@ class CorePlatform {
|
||||
bool made_volatile_data_dir_{};
|
||||
bool have_device_uuid_{};
|
||||
bool ran_base_post_init_{};
|
||||
bool have_ba_env_vals_{};
|
||||
millisecs_t start_time_millisecs_{};
|
||||
std::string device_name_;
|
||||
std::string legacy_device_uuid_;
|
||||
std::string volatile_data_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
|
||||
|
||||
@ -15,13 +15,6 @@ void LowLevelPythonDebugLog(const char* 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) {
|
||||
if (PyStatus_Exception(status)) {
|
||||
FatalError(std::string("Error in ") + where + ": "
|
||||
@ -337,4 +330,76 @@ void CorePython::LoggingCall(LogLevel loglevel, const std::string& msg) {
|
||||
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
|
||||
|
||||
@ -43,10 +43,6 @@ class CorePython {
|
||||
/// pent up ones) to Python.
|
||||
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.)
|
||||
/// Can be called from any thread at any time. If called before Python
|
||||
/// logging is available, logs locally using Logging::DisplayLog()
|
||||
@ -56,6 +52,13 @@ class CorePython {
|
||||
void VerifyPythonEnvironment();
|
||||
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_; }
|
||||
|
||||
private:
|
||||
|
||||
@ -75,45 +75,36 @@ static auto ParseArgValue(int argc, char** argv, int* i, const char* arg_long,
|
||||
return {};
|
||||
}
|
||||
|
||||
auto CoreConfig::FromCommandLineAndEnv(int argc, char** argv) -> CoreConfig {
|
||||
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.
|
||||
void CoreConfig::ApplyEnvVars() {
|
||||
if (auto* envval = getenv("BA_LIFECYCLE_LOG")) {
|
||||
if (!strcmp(envval, "1")) {
|
||||
cfg.lifecycle_log = true;
|
||||
lifecycle_log = true;
|
||||
}
|
||||
}
|
||||
if (auto* envval = getenv("BA_DEBUGGER_ATTACHED")) {
|
||||
if (!strcmp(envval, "1")) {
|
||||
cfg.debugger_attached = true;
|
||||
debugger_attached = true;
|
||||
}
|
||||
}
|
||||
if (auto* envval = getenv("BA_DEBUG_TIMING")) {
|
||||
if (!strcmp(envval, "1")) {
|
||||
cfg.debug_timing = true;
|
||||
debug_timing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REMOVE ME FOR 1.7.20 FINAL.
|
||||
if (explicit_bool(false)) {
|
||||
printf("TEMP: forcing BA_LIFECYCLE_LOG=1 during 1.7.20 development.\n");
|
||||
cfg.lifecycle_log = true;
|
||||
}
|
||||
|
||||
void CoreConfig::ApplyArgs(int argc, char** argv) {
|
||||
try {
|
||||
// First handle single-arg special cases like --help or --version.
|
||||
if (IsSingleArgSpecialCase(argc, argv, "--help", "-h")) {
|
||||
PrintHelp();
|
||||
cfg.immediate_return_code = 0;
|
||||
return cfg;
|
||||
immediate_return_code = 0;
|
||||
return;
|
||||
}
|
||||
if (IsSingleArgSpecialCase(argc, argv, "--version", "-v")) {
|
||||
printf("BallisticaKit %s build %d\n", kEngineVersion, kEngineBuildNumber);
|
||||
cfg.immediate_return_code = 0;
|
||||
return cfg;
|
||||
immediate_return_code = 0;
|
||||
return;
|
||||
}
|
||||
if (IsSingleArgSpecialCase(argc, argv, "--crash")) {
|
||||
int dummyval{};
|
||||
@ -126,7 +117,7 @@ auto CoreConfig::FromCommandLineAndEnv(int argc, char** argv) -> CoreConfig {
|
||||
if (explicit_bool(true)) {
|
||||
*invalid_ptr = 1;
|
||||
}
|
||||
return cfg;
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
while (i < argc) {
|
||||
if ((value = ParseArgValue(argc, argv, &i, "--command", "-c"))) {
|
||||
cfg.call_command = *value;
|
||||
call_command = *value;
|
||||
} else if ((value = ParseArgValue(argc, argv, &i, "--exec", "-e"))) {
|
||||
cfg.exec_command = *value;
|
||||
exec_command = *value;
|
||||
} else if ((value =
|
||||
ParseArgValue(argc, argv, &i, "--config-dir", "-C"))) {
|
||||
cfg.config_dir = *value;
|
||||
config_dir = *value;
|
||||
// Make sure what they passed exists.
|
||||
// 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
|
||||
// being more strict is ok when accepting user input.
|
||||
if (!std::filesystem::exists(*cfg.config_dir)) {
|
||||
printf("Error: Provided config dir does not exist: '%s'.",
|
||||
cfg.config_dir->c_str());
|
||||
if (!std::filesystem::is_directory(*config_dir)) {
|
||||
printf("Error: Provided config-dir path '%s' is not a directory.",
|
||||
config_dir->c_str());
|
||||
throw BadArgsException();
|
||||
}
|
||||
} else if ((value = ParseArgValue(argc, argv, &i, "--data-dir", "-d"))) {
|
||||
cfg.data_dir = *value;
|
||||
data_dir = *value;
|
||||
// Make sure what they passed exists.
|
||||
if (!std::filesystem::exists(*cfg.data_dir)) {
|
||||
printf("Error: Provided data dir does not exist: '%s'.",
|
||||
cfg.data_dir->c_str());
|
||||
if (!std::filesystem::is_directory(*data_dir)) {
|
||||
printf("Error: Provided data-dir path '%s' is not a directory.",
|
||||
data_dir->c_str());
|
||||
throw BadArgsException();
|
||||
}
|
||||
} 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.
|
||||
if (!std::filesystem::exists(*cfg.user_python_dir)) {
|
||||
printf("Error: Provided mods dir does not exist: '%s'.",
|
||||
cfg.user_python_dir->c_str());
|
||||
if (!std::filesystem::is_directory(*user_python_dir)) {
|
||||
printf("Error: Provided mods-dir path '%s' is not a directory.",
|
||||
user_python_dir->c_str());
|
||||
throw BadArgsException();
|
||||
}
|
||||
} else {
|
||||
@ -175,8 +166,25 @@ auto CoreConfig::FromCommandLineAndEnv(int argc, char** argv) -> CoreConfig {
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,17 @@ namespace ballistica::core {
|
||||
/// when initing the core feature-set.
|
||||
class CoreConfig {
|
||||
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.
|
||||
bool vr_mode{};
|
||||
@ -26,19 +36,19 @@ class CoreConfig {
|
||||
std::optional<int> immediate_return_code{};
|
||||
|
||||
/// 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{};
|
||||
|
||||
/// Python command to be run within the normal app loop.
|
||||
std::optional<std::string> exec_command{};
|
||||
|
||||
/// Explicitly set config dir.
|
||||
/// Explicitly passed config dir.
|
||||
std::optional<std::string> config_dir{};
|
||||
|
||||
/// Explicitly set data dir.
|
||||
/// Explicitly passed 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{};
|
||||
|
||||
/// Log various stages/times in the bootstrapping process.
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
#if BA_MONOLITHIC_BUILD && BA_DEFINE_MAIN
|
||||
auto main(int argc, char** argv) -> int {
|
||||
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
|
||||
// things such as '--help', in which case we're done.
|
||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
||||
namespace ballistica {
|
||||
|
||||
// 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";
|
||||
|
||||
#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.
|
||||
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
|
||||
// simply as a Python interpreter in that case; we don't do any
|
||||
// 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);
|
||||
}
|
||||
|
||||
// TEMP - bug hunting.
|
||||
l_core->platform->DebugLog("mm2");
|
||||
|
||||
// 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.
|
||||
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
|
||||
// dependency to it. Let's see if it's available.
|
||||
l_base = l_core->SoftImportBase();
|
||||
@ -109,9 +100,6 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
||||
// 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
|
||||
// things ready to rock, but there's no actual rocking quite yet.
|
||||
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."
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// TEMP - bug hunting.
|
||||
l_core->platform->DebugLog("mm5");
|
||||
|
||||
// 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
|
||||
// environment do that part).
|
||||
@ -165,7 +150,6 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (l_core) {
|
||||
l_core->platform->WillExitMain(false);
|
||||
return l_core->return_value;
|
||||
|
||||
@ -105,7 +105,8 @@ auto Python::GetPyString(PyObject* o) -> std::string {
|
||||
return PyUnicode_AsUTF8(o);
|
||||
}
|
||||
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>
|
||||
@ -220,6 +221,24 @@ auto Python::GetPyFloats(PyObject* o) -> std::vector<float> {
|
||||
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>
|
||||
auto GetPyIntsT(PyObject* o) -> std::vector<T> {
|
||||
assert(Python::HaveGIL());
|
||||
|
||||
@ -121,6 +121,7 @@ class Python {
|
||||
static auto GetPyInts(PyObject* o) -> std::vector<int>;
|
||||
static auto GetPyUInts64(PyObject* o) -> std::vector<uint64_t>;
|
||||
static auto GetPyPoint2D(PyObject* o) -> Point2D;
|
||||
static auto GetPyStrings(PyObject* o) -> std::list<std::string>;
|
||||
|
||||
/// Set Python exception from C++ Exception.
|
||||
static void SetPythonException(const Exception& exc);
|
||||
|
||||
@ -12,14 +12,14 @@ namespace ballistica {
|
||||
|
||||
// String based Python commands.
|
||||
|
||||
// Note to self: originally I though I'd be using this in a lot of places,
|
||||
// so I added the ability to compile once and run repeatedly, quietly capture
|
||||
// output instead of printing it, etc. Now, however, its usage is pretty
|
||||
// much limited to a few places such as handling stdin and the in-game console.
|
||||
// (Most places it is much cleaner to work with proper python modules and just
|
||||
// interact with PyObject* refs to them)
|
||||
// I should look and see if python's default high level calls would suffice
|
||||
// for these purposes and potentially kill this off.
|
||||
// Note to self: Originally I though I'd be using this in a lot of places,
|
||||
// so I added the ability to compile once and run repeatedly, quietly
|
||||
// capture output instead of printing it, etc. Now, however, its usage is
|
||||
// pretty much limited to a few places such as handling stdin and the
|
||||
// in-app console. (Most places it is much cleaner to work with proper
|
||||
// python modules and just interact with PyObject* refs to them) I should
|
||||
// look and see if python's default high level calls would suffice for these
|
||||
// purposes and potentially kill this off.
|
||||
class PythonCommand {
|
||||
public:
|
||||
PythonCommand();
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include "ballistica/core/python/core_python.h"
|
||||
#include "ballistica/core/support/base_soft.h"
|
||||
#include "ballistica/shared/foundation/types.h"
|
||||
#include "ballistica/shared/math/vector2f.h"
|
||||
#include "ballistica/shared/python/python.h"
|
||||
#include "ballistica/shared/python/python_sys.h"
|
||||
@ -13,7 +14,6 @@ namespace ballistica {
|
||||
// Note: implicitly using core globals here; our behavior is undefined
|
||||
// if core has not been imported by anyone yet.
|
||||
using core::g_base_soft;
|
||||
using core::g_core;
|
||||
|
||||
// Ignore a few things that python macros do.
|
||||
#pragma clang diagnostic push
|
||||
@ -179,6 +179,16 @@ auto PythonRef::ValueAsOptionalString() const -> std::optional<std::string> {
|
||||
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 {
|
||||
assert(Python::HaveGIL());
|
||||
ThrowIfUnset();
|
||||
@ -238,15 +248,8 @@ auto PythonRef::UnicodeCheck() const -> bool {
|
||||
return static_cast<bool>(PyUnicode_Check(obj_));
|
||||
}
|
||||
|
||||
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);
|
||||
static inline auto _HandleCallResults(PyObject* out, bool print_errors)
|
||||
-> PyObject* {
|
||||
if (!out) {
|
||||
if (print_errors) {
|
||||
// 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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
auto PythonRef::Call() const -> PythonRef {
|
||||
// NOTE: Using core globals directly here; normally don't do this.
|
||||
assert(g_core);
|
||||
return Call(
|
||||
g_core->python->objs().Get(core::CorePython::ObjID::kEmptyTuple).Get());
|
||||
auto PythonRef::Call(bool print_errors) const -> PythonRef {
|
||||
assert(obj_);
|
||||
assert(Python::HaveGIL());
|
||||
assert(CallableCheck());
|
||||
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());
|
||||
PythonRef args(Py_BuildValue("((ff))", val.x, val.y), PythonRef::kSteal);
|
||||
return Call(args);
|
||||
return Call(args.Get(), nullptr, print_errors);
|
||||
}
|
||||
|
||||
PythonRef::~PythonRef() { Release(); }
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#ifndef BALLISTICA_SHARED_PYTHON_PYTHON_REF_H_
|
||||
#define BALLISTICA_SHARED_PYTHON_PYTHON_REF_H_
|
||||
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
@ -166,6 +167,8 @@ class PythonRef {
|
||||
|
||||
auto ValueAsString() const -> std::string;
|
||||
auto ValueAsOptionalString() const -> std::optional<std::string>;
|
||||
auto ValueAsOptionalStringSequence() const
|
||||
-> std::optional<std::list<std::string>>;
|
||||
|
||||
auto ValueAsInt() const -> int64_t;
|
||||
|
||||
@ -185,10 +188,10 @@ class PythonRef {
|
||||
bool print_errors = true) const -> PythonRef {
|
||||
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.
|
||||
auto Call(const Vector2f& val) const -> PythonRef;
|
||||
auto Call(const Vector2f& val, bool print_errors = true) const -> PythonRef;
|
||||
|
||||
private:
|
||||
void ThrowIfUnset() const;
|
||||
|
||||
@ -271,6 +271,8 @@ def _writefuncs(
|
||||
returnstr = 'return (0.0, 0.0)'
|
||||
elif returns == 'str | None':
|
||||
returnstr = "return ''"
|
||||
elif returns == 'int | None':
|
||||
returnstr = 'return 0'
|
||||
elif returns == 'tuple[float, float, float, float]':
|
||||
returnstr = 'return (0.0, 0.0, 0.0, 0.0)'
|
||||
elif returns == 'bauiv1.Widget | None':
|
||||
|
||||
@ -105,7 +105,7 @@ class Pruner:
|
||||
self.paths = [os.path.abspath(p) for p in self.paths]
|
||||
|
||||
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):
|
||||
raise CleanError(
|
||||
f'Compile-commands not found at "{cmdspath}".'
|
||||
|
||||
@ -786,34 +786,16 @@ class SpinoffContext:
|
||||
if 'base' in self._src_omit_feature_sets:
|
||||
text = replace_exact(
|
||||
text,
|
||||
(
|
||||
'def _main() -> None:\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'
|
||||
),
|
||||
(
|
||||
'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'
|
||||
),
|
||||
' import babase\n',
|
||||
' # (Hack; spinoff disabled babase).\n'
|
||||
' if TYPE_CHECKING:\n'
|
||||
' from typing import Any\n'
|
||||
'\n'
|
||||
' # import babase\n'
|
||||
'\n'
|
||||
' babase: Any = None\n'
|
||||
' if bool(True):\n'
|
||||
" raise CleanError('babase not present')\n",
|
||||
label=src_path,
|
||||
)
|
||||
|
||||
@ -1587,7 +1569,7 @@ class SpinoffContext:
|
||||
os.chmod(dst_path_full, mode)
|
||||
else:
|
||||
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
|
||||
|
||||
@ -526,7 +526,7 @@ class AssetStager:
|
||||
'# Basically this will do:\n'
|
||||
'# import baenv; baenv.configure();'
|
||||
' 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)
|
||||
|
||||
|
||||
@ -25,16 +25,18 @@ class CleanError(Exception):
|
||||
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.
|
||||
|
||||
If the error has an empty message, prints nothing (not even a newline).
|
||||
"""
|
||||
from efro.terminal import Clr
|
||||
|
||||
if prefix:
|
||||
prefix = f'{prefix}: '
|
||||
errstr = str(self)
|
||||
if errstr:
|
||||
print(f'{Clr.SRED}{errstr}{Clr.RST}', flush=flush)
|
||||
print(f'{Clr.SRED}{prefix}{errstr}{Clr.RST}', flush=flush)
|
||||
|
||||
|
||||
class CommunicationError(Exception):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user