work on cmake-modular builds

This commit is contained in:
Eric 2023-07-21 14:23:46 -07:00
parent 15d9d1c7ce
commit aeb893294d
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
36 changed files with 1249 additions and 678 deletions

104
.efrocachemap generated
View File

@ -421,11 +421,11 @@
"build/assets/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/74/be/fe45a8417e95b6a2233c51992a26", "build/assets/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/74/be/fe45a8417e95b6a2233c51992a26",
"build/assets/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/48/ab/8cddfcde36a750856f3f81dd20c8", "build/assets/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/48/ab/8cddfcde36a750856f3f81dd20c8",
"build/assets/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/2b/46/8aedfa8741090247f04eb9e6df55", "build/assets/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/2b/46/8aedfa8741090247f04eb9e6df55",
"build/assets/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/a1/f9/645b8c7e1e99dd11446bc77005da", "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/83/87/06fc7255ebf8a895ad37d2dfa13d", "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/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/57/68/d03a19b9035cfae7cdc5377d889a",
"build/assets/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/b6/00/924583b899165757f412eef0dd01", "build/assets/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/b6/00/924583b899165757f412eef0dd01",
"build/assets/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/50/4c/4fb39f065b1a2f0320026a2e1b92", "build/assets/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/3f/e9/60a8f0ca529aa57b4f9cb7385abc",
"build/assets/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/76/65/32c67af5bd0144c2d63cab0516fa", "build/assets/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/76/65/32c67af5bd0144c2d63cab0516fa",
"build/assets/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/f3/ce/219840946cb8f9aa6d3e25927ab3", "build/assets/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/f3/ce/219840946cb8f9aa6d3e25927ab3",
"build/assets/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/d6/9080783d5c9dcc0af737f02b6f1e", "build/assets/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/d6/9080783d5c9dcc0af737f02b6f1e",
@ -438,7 +438,7 @@
"build/assets/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/23/6f/8547ba09722b7c7f5b8333986984", "build/assets/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/23/6f/8547ba09722b7c7f5b8333986984",
"build/assets/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/a6/5d/78f912e9a89f98de004405167a6a", "build/assets/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/a6/5d/78f912e9a89f98de004405167a6a",
"build/assets/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/88/ee/0cda537bab9ac827def5e236fe1a", "build/assets/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/88/ee/0cda537bab9ac827def5e236fe1a",
"build/assets/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/00/ba/cf1b8bb9f7914f64647d4665b0a8", "build/assets/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/a9/b5/10de2f3928d8c1f4887e0975743f",
"build/assets/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/58/3b/ae1ecc04375cee089a82359110b7", "build/assets/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/58/3b/ae1ecc04375cee089a82359110b7",
"build/assets/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/67/44/40ada7b8e76adceb2129d7668df6", "build/assets/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/67/44/40ada7b8e76adceb2129d7668df6",
"build/assets/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/bd/c1/3f8632adda5517059323d928f192", "build/assets/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/bd/c1/3f8632adda5517059323d928f192",
@ -450,13 +450,13 @@
"build/assets/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/aa/99/f9f597787fe4e09c8ab53fe2e081", "build/assets/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/aa/99/f9f597787fe4e09c8ab53fe2e081",
"build/assets/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/d7/45/2dd72ac0e51680cb39b5ebaa1c69", "build/assets/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/d7/45/2dd72ac0e51680cb39b5ebaa1c69",
"build/assets/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/27/96/2d53dc3f7dd4e877cd40faafeeef", "build/assets/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/27/96/2d53dc3f7dd4e877cd40faafeeef",
"build/assets/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/bd/5e/80c74f96bb50d270396d437d6750", "build/assets/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/45/dd/ce6d9dd446293f5e0ae541f36943",
"build/assets/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/77/d6/71f10613291ebf9c71da66f18a18", "build/assets/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/77/d6/71f10613291ebf9c71da66f18a18",
"build/assets/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/c7/fc/5ed7bd686839ec1a867763248cf9", "build/assets/ba_data/data/languages/tamil.json": "https://files.ballistica.net/cache/ba1/c7/fc/5ed7bd686839ec1a867763248cf9",
"build/assets/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/33/f6/3753c9af9a5b238d229a0bf23fbc", "build/assets/ba_data/data/languages/thai.json": "https://files.ballistica.net/cache/ba1/33/f6/3753c9af9a5b238d229a0bf23fbc",
"build/assets/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/0a/97/f1f948f6587ea7d40b639aba67ce", "build/assets/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/0a/97/f1f948f6587ea7d40b639aba67ce",
"build/assets/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/97/4a/399422e3061fdd82f66591283397", "build/assets/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/97/4a/399422e3061fdd82f66591283397",
"build/assets/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/e4/74/5c85bc56487bb715712c8b90a1eb", "build/assets/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/b0/e3/d73ccf96c5fa490a54f090ee77a5",
"build/assets/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/92/1c/d1e50f60fe3e101f246e172750ba", "build/assets/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/92/1c/d1e50f60fe3e101f246e172750ba",
"build/assets/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/1d/d3/01d490643088a435ce75df971054", "build/assets/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/1d/d3/01d490643088a435ce75df971054",
"build/assets/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/6a/ea/74805f4880cc11237c5734a24422", "build/assets/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/6a/ea/74805f4880cc11237c5734a24422",
@ -951,7 +951,7 @@
"build/assets/ba_data/python-site-packages/certifi/cacert.pem": "https://files.ballistica.net/cache/ba1/6a/c2/9a6bccca11cd2ed7e16e27dfccec", "build/assets/ba_data/python-site-packages/certifi/cacert.pem": "https://files.ballistica.net/cache/ba1/6a/c2/9a6bccca11cd2ed7e16e27dfccec",
"build/assets/ba_data/python-site-packages/certifi/core.py": "https://files.ballistica.net/cache/ba1/1b/50/5388f1475fabd1b60031f985271c", "build/assets/ba_data/python-site-packages/certifi/core.py": "https://files.ballistica.net/cache/ba1/1b/50/5388f1475fabd1b60031f985271c",
"build/assets/ba_data/python-site-packages/typing_extensions.py": "https://files.ballistica.net/cache/ba1/08/4d/93bb609d798a3930dfb5e25eba59", "build/assets/ba_data/python-site-packages/typing_extensions.py": "https://files.ballistica.net/cache/ba1/08/4d/93bb609d798a3930dfb5e25eba59",
"build/assets/ba_data/python-site-packages/yaml/__init__.py": "https://files.ballistica.net/cache/ba1/55/7c/37ea8dbd4fa4d6dac97f399b6fdd", "build/assets/ba_data/python-site-packages/yaml/__init__.py": "https://files.ballistica.net/cache/ba1/2b/74/7e5772c203377222afc888ac6b71",
"build/assets/ba_data/python-site-packages/yaml/composer.py": "https://files.ballistica.net/cache/ba1/ce/f8/71e1f5f99ba2a7c44941b70afb06", "build/assets/ba_data/python-site-packages/yaml/composer.py": "https://files.ballistica.net/cache/ba1/ce/f8/71e1f5f99ba2a7c44941b70afb06",
"build/assets/ba_data/python-site-packages/yaml/constructor.py": "https://files.ballistica.net/cache/ba1/8a/15/e361e34b79491c81553bb3534062", "build/assets/ba_data/python-site-packages/yaml/constructor.py": "https://files.ballistica.net/cache/ba1/8a/15/e361e34b79491c81553bb3534062",
"build/assets/ba_data/python-site-packages/yaml/cyaml.py": "https://files.ballistica.net/cache/ba1/9b/11/cba12e6f1cf2efe1725a20d7e1e5", "build/assets/ba_data/python-site-packages/yaml/cyaml.py": "https://files.ballistica.net/cache/ba1/9b/11/cba12e6f1cf2efe1725a20d7e1e5",
@ -4068,50 +4068,50 @@
"build/assets/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/2d/ef/5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/2d/ef/5335207d41b21b9823f6805997f1",
"build/assets/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/b0/8a/55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/b0/8a/55e2e77623fe657bea24f223a3ae",
"build/assets/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/86/5b/2af4d1e26a1a8073c89acb06e599", "build/assets/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/86/5b/2af4d1e26a1a8073c89acb06e599",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/a8/5e/e644cd4120304fba4d4dbd9762e2", "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/31/48/05c88daed3cf3e90f5a051ec6a0c",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/92/73/0a1325df721b51d0c9f2e0f6f075", "build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/72/f9/d85a330987d81ffc895fc8ec922c",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/24/f8/b372c8e02345a5540bd976069de8", "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/1a/92/6d465e12a3460498d978f31abf15",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/81/5d/8368c53554a9b997f0a1d38c0ced", "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/0c/0e/1b219bc8d0b6d7ccf57bdd721860",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/cb/90/6f74ab7d83e5ff9db887f391664a", "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/4a/7f/1068c0311d88aa8145e487f0e30b",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/cd/51/6639bbf611e918b21c1676b25764", "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/1d/0d/fd0d55be1b0e69de4c4667d34644",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/d1/4b/5f2cb963955fd973bd7498c57519", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/3f/d0/cec6952032a5ddc8c1a63b1e1ba3",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/9b/9f/1e1d79b604749c2033e7fad06394", "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/a7/6e/b40ca2ec7dde8c0e9edb0db376c1",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/97/f6/2f0e7dba9be2437f43dc4af5e449", "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/fe/88/123692ae9ffbc97aaddbd51c0f30",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/2e/22/297bedb0cbfb169fb9ba607bff1b", "build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/16/31/b64154143f4e903388b9013b41c7",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/c6/3e/6b09e07290a01483186b2ca44f8b", "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/c0/f9/aea06ce01cffb7931aca46285316",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/9e/c9/89f8f396ba8597453d81542f6ff6", "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/d0/a0/a9a8c9fe3addcc0a9f7a014acef1",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/0b/d8/4b6df9ec36d59a5560615c763bbf", "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/66/e3/d827e9edb1363d55a85636fc5f58",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/2d/5e/f6e1619a73c21c886425d878b96a", "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/b4/05/e5a12646d900aeeaa7e974dabda2",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/b6/4b/c7e9a14a16d69b20313f7007662c", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/94/16/24b8715c0f5c2eb6699ff20e594d",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/2c/00/fe4d13eb53c0d825da2750b30cec", "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/83/6d/d914432abe2d071890a6b3e2d6f1",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/69/19/13f59849fe2a31eac8a350db2e12", "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/10/b7/04b0835c36649b8bcd70abf2f3d7",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/01/ab/f243ffaa211fd9463cc7ede10f29", "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/0a/13/807d5e92e146b5e9bfc679dbd44b",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/87/d3/88a28894dc15e511f3ba56f44267", "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/3f/1e/2970e115041bc1828b3b2b8ef4db",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/b5/1e/bb7075104c420ca1c0663d24768c", "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/9f/28/bf466437892861a399375c864a0d",
"build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/84/aa/534f35b6499762739646ea173382", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/4e/69/3d3715ffb88e61962dff80e52fa0",
"build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/25/2f/3bd787d6debb2c4073fd6c2e8098", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/df/78/f138dbf92a93dcd647831fb8fde4",
"build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/84/aa/534f35b6499762739646ea173382", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/4e/69/3d3715ffb88e61962dff80e52fa0",
"build/prefab/lib/linux_arm64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/25/2f/3bd787d6debb2c4073fd6c2e8098", "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/df/78/f138dbf92a93dcd647831fb8fde4",
"build/prefab/lib/linux_x86_64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/b8/01/153180116f1ab302aa8e6fd9ca9c", "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/4d/45/84cd8d36933f680c4c5ea6ed56e3",
"build/prefab/lib/linux_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/93/1c/1aba110dcf69d8651b428f2927ed", "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/31/e8/ebc78517b4f6c3dba799d96b6770",
"build/prefab/lib/linux_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/b8/01/153180116f1ab302aa8e6fd9ca9c", "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/4d/45/84cd8d36933f680c4c5ea6ed56e3",
"build/prefab/lib/linux_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/93/1c/1aba110dcf69d8651b428f2927ed", "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/31/e8/ebc78517b4f6c3dba799d96b6770",
"build/prefab/lib/mac_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/4b/1a/21983185f7bdd78842b572535dad", "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/16/31/fa50eca4cccba5819aba7598cdd2",
"build/prefab/lib/mac_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/3c/1d/d7864d7822c64ee06cee0dde659e", "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/80/f5/1e75ca051bcc9cf5622443368820",
"build/prefab/lib/mac_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/4b/1a/21983185f7bdd78842b572535dad", "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/16/31/fa50eca4cccba5819aba7598cdd2",
"build/prefab/lib/mac_arm64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/3c/1d/d7864d7822c64ee06cee0dde659e", "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/80/f5/1e75ca051bcc9cf5622443368820",
"build/prefab/lib/mac_x86_64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/65/ab/524fe2f6a339b6480173c2c1624a", "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/34/26/fe4dacd23b76a39c024e220a6851",
"build/prefab/lib/mac_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/47/61/eca0961c54b2eae2cf65fac7848d", "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/84/7d/952ba7e47c98635853b6b3e046fa",
"build/prefab/lib/mac_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/06/5c/90c3a49e16a004e2db71909af919", "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/ad/de/141e3f5ea646f9d359a7edc40524",
"build/prefab/lib/mac_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/47/61/eca0961c54b2eae2cf65fac7848d", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/84/7d/952ba7e47c98635853b6b3e046fa",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/d3/34/d2fa72d15a085424bad4157a6f2e", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/0d/e3/9a30e693bc57d27a093019988e2d",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/56/5f/6cde7712eebd76bcd9081b1d063a", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/b3/df/933a84818c7a7f7059c5d2aef159",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/8e/bb/cde5d48031a147358f49372348fc", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/76/46/7e4792528fdc5ee7b432b8239567",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/82/e5/7d8d72481b84b81a3ec2b85cddf1", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/03/54/742e4cae6ce81180e6977ccf3cd1",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/74/11/5059d262beb03fda192c967760ea", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/35/1b/cd6f88e5a7dda82848362d3ee41e",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/bf/57/94af76a5f7f51c10e9725730469e", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/8f/b4/32805c7732aa03bc4417aed0f61b",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/fc/56/19374bffec117190ae9c132cff68", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/7a/10/3c2abaa7fa0280fe5111209a9fd5",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/c6/c9/b6828fe5295e6d5df08fad9ebf3f", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/60/88/4d71bc815388e9d867d8ffa95c61",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/f8/85/fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/f8/85/fed7f2ed98ff2ba271f9dbe3391c",
"src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/f8/cd/3af311ac63147882590123b78318", "src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/f8/cd/3af311ac63147882590123b78318",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/3e/7a/203e2a5d2b5bb42cfe3fd2fe16c2", "src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/3e/7a/203e2a5d2b5bb42cfe3fd2fe16c2",
@ -4119,7 +4119,7 @@
"src/ballistica/classic/mgen/pyembed/binding_classic.inc": "https://files.ballistica.net/cache/ba1/3c/eb/412513963f0818ab39c58bf292e3", "src/ballistica/classic/mgen/pyembed/binding_classic.inc": "https://files.ballistica.net/cache/ba1/3c/eb/412513963f0818ab39c58bf292e3",
"src/ballistica/core/mgen/pyembed/binding_core.inc": "https://files.ballistica.net/cache/ba1/9d/0a/3c9636138e35284923e0c8311c69", "src/ballistica/core/mgen/pyembed/binding_core.inc": "https://files.ballistica.net/cache/ba1/9d/0a/3c9636138e35284923e0c8311c69",
"src/ballistica/core/mgen/pyembed/env.inc": "https://files.ballistica.net/cache/ba1/8b/e4/6e5818f360d10b7b0224a9e91d07", "src/ballistica/core/mgen/pyembed/env.inc": "https://files.ballistica.net/cache/ba1/8b/e4/6e5818f360d10b7b0224a9e91d07",
"src/ballistica/core/mgen/python_modules_monolithic.h": "https://files.ballistica.net/cache/ba1/c4/8c/4f5294e83eb1ff22edffebf2bf8b", "src/ballistica/core/mgen/python_modules_monolithic.h": "https://files.ballistica.net/cache/ba1/fb/96/7ed1c7db0c77d8deb4f00a7103c5",
"src/ballistica/scene_v1/mgen/pyembed/binding_scene_v1.inc": "https://files.ballistica.net/cache/ba1/d8/0f/970053099b3044204bfe29ddefce", "src/ballistica/scene_v1/mgen/pyembed/binding_scene_v1.inc": "https://files.ballistica.net/cache/ba1/d8/0f/970053099b3044204bfe29ddefce",
"src/ballistica/template_fs/mgen/pyembed/binding_template_fs.inc": "https://files.ballistica.net/cache/ba1/44/a4/5492db057bf7f7158c3b0fa11f0f", "src/ballistica/template_fs/mgen/pyembed/binding_template_fs.inc": "https://files.ballistica.net/cache/ba1/44/a4/5492db057bf7f7158c3b0fa11f0f",
"src/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc": "https://files.ballistica.net/cache/ba1/6e/98/2bd0dda68e8b821f5b5cc18ce1d5" "src/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc": "https://files.ballistica.net/cache/ba1/6e/98/2bd0dda68e8b821f5b5cc18ce1d5"

View File

@ -233,6 +233,8 @@
<w>ballistica's</w> <w>ballistica's</w>
<w>ballisticakit</w> <w>ballisticakit</w>
<w>ballisticakitcb</w> <w>ballisticakitcb</w>
<w>ballisticakitso</w>
<w>ballisticaplus</w>
<w>bamaster</w> <w>bamaster</w>
<w>bamasteraddr</w> <w>bamasteraddr</w>
<w>bamasterlegacy</w> <w>bamasterlegacy</w>
@ -318,6 +320,7 @@
<w>bmas</w> <w>bmas</w>
<w>bmasl</w> <w>bmasl</w>
<w>bmcjphh</w> <w>bmcjphh</w>
<w>bmodfeaturesets</w>
<w>bname</w> <w>bname</w>
<w>bndl</w> <w>bndl</w>
<w>boffs</w> <w>boffs</w>
@ -522,6 +525,7 @@
<w>clrred</w> <w>clrred</w>
<w>cmakelist</w> <w>cmakelist</w>
<w>cmakelists</w> <w>cmakelists</w>
<w>cmakemodular</w>
<w>cmakeserver</w> <w>cmakeserver</w>
<w>cmath</w> <w>cmath</w>
<w>cmathmodule</w> <w>cmathmodule</w>
@ -729,6 +733,7 @@
<w>dingsound</w> <w>dingsound</w>
<w>dingsoundhigh</w> <w>dingsoundhigh</w>
<w>dinl</w> <w>dinl</w>
<w>dir's</w>
<w>dirfilter</w> <w>dirfilter</w>
<w>dirmanifest</w> <w>dirmanifest</w>
<w>dirname</w> <w>dirname</w>
@ -832,6 +837,7 @@
<w>dusing</w> <w>dusing</w>
<w>dval</w> <w>dval</w>
<w>dxml</w> <w>dxml</w>
<w>dylibdir</w>
<w>dynload</w> <w>dynload</w>
<w>eachother</w> <w>eachother</w>
<w>eaddrnotavail</w> <w>eaddrnotavail</w>
@ -894,6 +900,7 @@
<w>enumvalue</w> <w>enumvalue</w>
<w>enval</w> <w>enval</w>
<w>envcfg</w> <w>envcfg</w>
<w>envglobals</w>
<w>envhash</w> <w>envhash</w>
<w>envname</w> <w>envname</w>
<w>envs</w> <w>envs</w>
@ -930,6 +937,7 @@
<w>excludetypes</w> <w>excludetypes</w>
<w>excstr</w> <w>excstr</w>
<w>exec'ed</w> <w>exec'ed</w>
<w>exec'ing</w>
<w>execcode</w> <w>execcode</w>
<w>execed</w> <w>execed</w>
<w>execing</w> <w>execing</w>
@ -982,6 +990,7 @@
<w>fdata</w> <w>fdata</w>
<w>fdataraw</w> <w>fdataraw</w>
<w>fdcount</w> <w>fdcount</w>
<w>fdcwd</w>
<w>fdesc</w> <w>fdesc</w>
<w>fdict</w> <w>fdict</w>
<w>fdirs</w> <w>fdirs</w>
@ -1103,6 +1112,8 @@
<w>fsconfigpath</w> <w>fsconfigpath</w>
<w>fsdf</w> <w>fsdf</w>
<w>fset</w> <w>fset</w>
<w>fsetmfilenames</w>
<w>fsetmfilenamevals</w>
<w>fsetname</w> <w>fsetname</w>
<w>fsets</w> <w>fsets</w>
<w>fsettings</w> <w>fsettings</w>
@ -1130,6 +1141,7 @@
<w>fullpath</w> <w>fullpath</w>
<w>fullprice</w> <w>fullprice</w>
<w>fullscreen</w> <w>fullscreen</w>
<w>fullstr</w>
<w>fulltest</w> <w>fulltest</w>
<w>funcname</w> <w>funcname</w>
<w>funcnames</w> <w>funcnames</w>
@ -1403,6 +1415,7 @@
<w>initializers</w> <w>initializers</w>
<w>initialplayerinfos</w> <w>initialplayerinfos</w>
<w>initing</w> <w>initing</w>
<w>initname</w>
<w>inits</w> <w>inits</w>
<w>inittab</w> <w>inittab</w>
<w>inmobi</w> <w>inmobi</w>
@ -1419,6 +1432,7 @@
<w>insta</w> <w>insta</w>
<w>installdir</w> <w>installdir</w>
<w>instancer</w> <w>instancer</w>
<w>instpath</w>
<w>interfacetype</w> <w>interfacetype</w>
<w>internalmodule</w> <w>internalmodule</w>
<w>internalsrc</w> <w>internalsrc</w>
@ -1551,6 +1565,7 @@
<w>lfval</w> <w>lfval</w>
<w>libballistica</w> <w>libballistica</w>
<w>libballisticakit</w> <w>libballisticakit</w>
<w>libballisticaplus</w>
<w>libbz</w> <w>libbz</w>
<w>libbzip</w> <w>libbzip</w>
<w>libcrypto</w> <w>libcrypto</w>
@ -1721,6 +1736,7 @@
<w>maxw</w> <w>maxw</w>
<w>maxwait</w> <w>maxwait</w>
<w>maxwidth</w> <w>maxwidth</w>
<w>mbstowcs</w>
<w>mbytecount</w> <w>mbytecount</w>
<w>mdiv</w> <w>mdiv</w>
<w>mdocs</w> <w>mdocs</w>
@ -1741,6 +1757,7 @@
<w>metaprogramming</w> <w>metaprogramming</w>
<w>metascan</w> <w>metascan</w>
<w>meteorshower</w> <w>meteorshower</w>
<w>mfilename</w>
<w>mfpath</w> <w>mfpath</w>
<w>mhash</w> <w>mhash</w>
<w>mhbegin</w> <w>mhbegin</w>
@ -1984,6 +2001,7 @@
<w>olde</w> <w>olde</w>
<w>oldlady</w> <w>oldlady</w>
<w>oldpath</w> <w>oldpath</w>
<w>oldpaths</w>
<w>oldtoken</w> <w>oldtoken</w>
<w>olduuid</w> <w>olduuid</w>
<w>olduuids</w> <w>olduuids</w>
@ -2003,7 +2021,9 @@
<w>opposingbody</w> <w>opposingbody</w>
<w>opposingnode</w> <w>opposingnode</w>
<w>opstr</w> <w>opstr</w>
<w>optnm</w>
<w>optparse</w> <w>optparse</w>
<w>optstuff</w>
<w>orchestrahitsound</w> <w>orchestrahitsound</w>
<w>origwrapper</w> <w>origwrapper</w>
<w>ortho</w> <w>ortho</w>
@ -2019,6 +2039,7 @@
<w>ourhash</w> <w>ourhash</w>
<w>ourname</w> <w>ourname</w>
<w>ourpackage</w> <w>ourpackage</w>
<w>ourpaths</w>
<w>ourself</w> <w>ourself</w>
<w>outdata</w> <w>outdata</w>
<w>outdelay</w> <w>outdelay</w>
@ -2065,6 +2086,7 @@
<w>pathbar</w> <w>pathbar</w>
<w>pathcapture</w> <w>pathcapture</w>
<w>pathdst</w> <w>pathdst</w>
<w>pathlen</w>
<w>pathlib</w> <w>pathlib</w>
<w>pathlist</w> <w>pathlist</w>
<w>pathnames</w> <w>pathnames</w>
@ -2357,8 +2379,10 @@
<w>pythondontwritebytecode</w> <w>pythondontwritebytecode</w>
<w>pythonenumsmodule</w> <w>pythonenumsmodule</w>
<w>pythonhashseed</w> <w>pythonhashseed</w>
<w>pythonoptimize</w>
<w>pythonpath</w> <w>pythonpath</w>
<w>pythonpaths</w> <w>pythonpaths</w>
<w>pythonutf</w>
<w>pythonw</w> <w>pythonw</w>
<w>pytree</w> <w>pytree</w>
<w>pytz</w> <w>pytz</w>
@ -2390,6 +2414,8 @@
<w>readexactly</w> <w>readexactly</w>
<w>readline</w> <w>readline</w>
<w>readlines</w> <w>readlines</w>
<w>readlink</w>
<w>readlinkat</w>
<w>realpath</w> <w>realpath</w>
<w>realsies</w> <w>realsies</w>
<w>recache</w> <w>recache</w>
@ -2708,10 +2734,12 @@
<w>sred</w> <w>sred</w>
<w>sriyakaal</w> <w>sriyakaal</w>
<w>sshd</w> <w>sshd</w>
<w>ssize</w>
<w>sslcontext</w> <w>sslcontext</w>
<w>sslproto</w> <w>sslproto</w>
<w>ssval</w> <w>ssval</w>
<w>stackstr</w> <w>stackstr</w>
<w>stager</w>
<w>standin</w> <w>standin</w>
<w>starscale</w> <w>starscale</w>
<w>startercache</w> <w>startercache</w>
@ -2820,6 +2848,7 @@
<w>syncitem</w> <w>syncitem</w>
<w>syncitems</w> <w>syncitems</w>
<w>synclist</w> <w>synclist</w>
<w>syscall</w>
<w>sysconfigdata</w> <w>sysconfigdata</w>
<w>sysctl</w> <w>sysctl</w>
<w>syslogmodule</w> <w>syslogmodule</w>
@ -3186,6 +3215,7 @@
<w>winapi</w> <w>winapi</w>
<w>winbeast</w> <w>winbeast</w>
<w>wincfg</w> <w>wincfg</w>
<w>wincfglc</w>
<w>wincount</w> <w>wincount</w>
<w>winempty</w> <w>winempty</w>
<w>winnergroup</w> <w>winnergroup</w>

View File

@ -1,4 +1,38 @@
### 1.7.23 (build 21171, api 8, 2023-07-16) ### 1.7.24 (build 21183, api 8, 2023-07-21)
- 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
'modular'. The traditional form of the app, where we bootstrap Python
ourselves inside a standalone binary, is called 'monolithic'. To build and run
Ballistica in modular form, you can do `make cmake-modular`. This should make
it easier to use certain things like Python debuggers with Ballistica. While I
expect most builds of the game to remain monolithic, this may become the
default for certain situations such as server builds or possibly Linux builds
if it seems beneficial. We'll see. Modular mode should work on Linux and Mac
currently; other platforms remain monolithic-only for now.
- Changed path wrangling a bit in baenv.py. All ballistica Python paths
(including python-site-packages) are now placed before any other existing
Python paths. This should provide a more consistent environment and means
Ballistica will always use its own version of things like yaml or certifi or
typing_extensions instead of one the user has installed via pip. Holler if you
run into any problems because of this and we can make an option to use the old
behavior where Ballistica's app and site paths get placed at the end.
- It is now possible to manually run the app loop even on monolithic builds;
just do `PYTHONPATH=ba_data/python ./ballisticacore -c "import baenv;
baenv.configure(); import babase; babase.app.run()"`. This is basically the
same thing modular builds are doing except that they use a regular Python
interpreter instead of the ballisticakit binary.
- Cleaned up the `tools/pcommand stage_assets` command. It now always expects a
separate `-debug` or `-release` arg. So old commands such as `tools/pcommand
stage_assets -win-Win32-Debug .` now look like `tools/pcommand stage_assets
-win-Win32 -debug .`. Please holler if you run into any broken asset-staging
calls in the Makefile/etc.
- `FeatureSet.has_native_python_module` has been renamed to
`FeatureSet.has_python_binary_module` for better consistency with related
functionality.
### 1.7.23 (build 21178, api 8, 2023-07-19)
- Network security improvements. (Thanks Dliwk!) - Network security improvements. (Thanks Dliwk!)
- You can now double click a chat message to copy it. (Thanks Vishal332008!) - You can now double click a chat message to copy it. (Thanks Vishal332008!)

View File

@ -243,16 +243,16 @@ prefab-mac-arm64-gui-debug: prefab-mac-arm64-gui-debug-build
prefab-mac-x86-64-gui-debug-build: prereqs assets-cmake \ prefab-mac-x86-64-gui-debug-build: prereqs assets-cmake \
build/prefab/full/mac_x86_64_gui/debug/ballisticakit build/prefab/full/mac_x86_64_gui/debug/ballisticakit
@$(STAGE_ASSETS) -cmake build/prefab/full/mac_x86_64_gui/debug @$(STAGE_ASSETS) -cmake -debug build/prefab/full/mac_x86_64_gui/debug
prefab-mac-arm64-gui-debug-build: prereqs assets-cmake \ prefab-mac-arm64-gui-debug-build: prereqs assets-cmake \
build/prefab/full/mac_arm64_gui/debug/ballisticakit build/prefab/full/mac_arm64_gui/debug/ballisticakit
@$(STAGE_ASSETS) -cmake build/prefab/full/mac_arm64_gui/debug @$(STAGE_ASSETS) -cmake -debug build/prefab/full/mac_arm64_gui/debug
build/prefab/full/mac_%_gui/debug/ballisticakit: .efrocachemap build/prefab/full/mac_%_gui/debug/ballisticakit: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
build/prefab/lib/mac_%_gui/debug/libballistica_plus.a: .efrocachemap build/prefab/lib/mac_%_gui/debug/libballisticaplus.a: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
# Mac gui release: # Mac gui release:
@ -273,16 +273,16 @@ prefab-mac-arm64-gui-release: prefab-mac-arm64-gui_release-build
prefab-mac-x86-64-gui-release-build: prereqs assets-cmake \ prefab-mac-x86-64-gui-release-build: prereqs assets-cmake \
build/prefab/full/mac_x86_64_gui/release/ballisticakit build/prefab/full/mac_x86_64_gui/release/ballisticakit
@$(STAGE_ASSETS) -cmake build/prefab/full/mac_x86_64_gui/release @$(STAGE_ASSETS) -cmake -release build/prefab/full/mac_x86_64_gui/release
prefab-mac-arm64-gui-release-build: prereqs assets-cmake \ prefab-mac-arm64-gui-release-build: prereqs assets-cmake \
build/prefab/full/mac_arm64_gui/release/ballisticakit build/prefab/full/mac_arm64_gui/release/ballisticakit
@$(STAGE_ASSETS) -cmake build/prefab/full/mac_arm64_gui/release @$(STAGE_ASSETS) -cmake -release build/prefab/full/mac_arm64_gui/release
build/prefab/full/mac_%_gui/release/ballisticakit: .efrocachemap build/prefab/full/mac_%_gui/release/ballisticakit: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
build/prefab/lib/mac_%_gui/release/libballistica_plus.a: .efrocachemap build/prefab/lib/mac_%_gui/release/libballisticaplus.a: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
# Mac server debug: # Mac server debug:
@ -312,7 +312,7 @@ prefab-mac-arm64-server-debug-build: prereqs assets-server \
build/prefab/full/mac_%_server/debug/dist/ballisticakit_headless: .efrocachemap build/prefab/full/mac_%_server/debug/dist/ballisticakit_headless: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
build/prefab/lib/mac_%_server/debug/libballistica_plus.a: .efrocachemap build/prefab/lib/mac_%_server/debug/libballisticaplus.a: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
# Mac server release: # Mac server release:
@ -344,7 +344,7 @@ prefab-mac-arm64-server-release-build: prereqs assets-server \
build/prefab/full/mac_%_server/release/dist/ballisticakit_headless: .efrocachemap build/prefab/full/mac_%_server/release/dist/ballisticakit_headless: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
build/prefab/lib/mac_%_server/release/libballistica_plus.a: .efrocachemap build/prefab/lib/mac_%_server/release/libballisticaplus.a: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
# Linux gui debug: # Linux gui debug:
@ -365,16 +365,16 @@ prefab-linux-arm64-gui-debug: prefab-linux-arm64-gui-debug-build
prefab-linux-x86-64-gui-debug-build: prereqs assets-cmake \ prefab-linux-x86-64-gui-debug-build: prereqs assets-cmake \
build/prefab/full/linux_x86_64_gui/debug/ballisticakit build/prefab/full/linux_x86_64_gui/debug/ballisticakit
@$(STAGE_ASSETS) -cmake build/prefab/full/linux_x86_64_gui/debug @$(STAGE_ASSETS) -cmake -debug build/prefab/full/linux_x86_64_gui/debug
prefab-linux-arm64-gui-debug-build: prereqs assets-cmake \ prefab-linux-arm64-gui-debug-build: prereqs assets-cmake \
build/prefab/full/linux_arm64_gui/debug/ballisticakit build/prefab/full/linux_arm64_gui/debug/ballisticakit
@$(STAGE_ASSETS) -cmake build/prefab/full/linux_arm64_gui/debug @$(STAGE_ASSETS) -cmake -debug build/prefab/full/linux_arm64_gui/debug
build/prefab/full/linux_%_gui/debug/ballisticakit: .efrocachemap build/prefab/full/linux_%_gui/debug/ballisticakit: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
build/prefab/lib/linux_%_gui/debug/libballistica_plus.a: .efrocachemap build/prefab/lib/linux_%_gui/debug/libballisticaplus.a: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
# Linux gui release: # Linux gui release:
@ -395,16 +395,16 @@ prefab-linux-arm64-gui-release: prefab-linux-arm64-gui-release-build
prefab-linux-x86-64-gui-release-build: prereqs assets-cmake \ prefab-linux-x86-64-gui-release-build: prereqs assets-cmake \
build/prefab/full/linux_x86_64_gui/release/ballisticakit build/prefab/full/linux_x86_64_gui/release/ballisticakit
@$(STAGE_ASSETS) -cmake build/prefab/full/linux_x86_64_gui/release @$(STAGE_ASSETS) -cmake -release build/prefab/full/linux_x86_64_gui/release
prefab-linux-arm64-gui-release-build: prereqs assets-cmake \ prefab-linux-arm64-gui-release-build: prereqs assets-cmake \
build/prefab/full/linux_arm64_gui/release/ballisticakit build/prefab/full/linux_arm64_gui/release/ballisticakit
@$(STAGE_ASSETS) -cmake build/prefab/full/linux_arm64_gui/release @$(STAGE_ASSETS) -cmake -release build/prefab/full/linux_arm64_gui/release
build/prefab/full/linux_%_gui/release/ballisticakit: .efrocachemap build/prefab/full/linux_%_gui/release/ballisticakit: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
build/prefab/lib/linux_%_gui/release/libballistica_plus.a: .efrocachemap build/prefab/lib/linux_%_gui/release/libballisticaplus.a: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
# Linux server debug: # Linux server debug:
@ -436,7 +436,7 @@ prefab-linux-arm64-server-debug-build: prereqs assets-server \
build/prefab/full/linux_%_server/debug/dist/ballisticakit_headless: .efrocachemap build/prefab/full/linux_%_server/debug/dist/ballisticakit_headless: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
build/prefab/lib/linux_%_server/debug/libballistica_plus.a: .efrocachemap build/prefab/lib/linux_%_server/debug/libballisticaplus.a: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
# Linux server release: # Linux server release:
@ -468,7 +468,7 @@ prefab-linux-arm64-server-release-build: prereqs assets-server \
build/prefab/full/linux_%_server/release/dist/ballisticakit_headless: .efrocachemap build/prefab/full/linux_%_server/release/dist/ballisticakit_headless: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
build/prefab/lib/linux_%_server/release/libballistica_plus.a: .efrocachemap build/prefab/lib/linux_%_server/release/libballisticaplus.a: .efrocachemap
@tools/pcommand efrocache_get $@ @tools/pcommand efrocache_get $@
# Windows gui debug: # Windows gui debug:
@ -482,7 +482,7 @@ prefab-windows-x86-gui-debug: prefab-windows-x86-gui-debug-build
prefab-windows-x86-gui-debug-build: prereqs assets-windows-$(WINPLAT_X86) \ prefab-windows-x86-gui-debug-build: prereqs assets-windows-$(WINPLAT_X86) \
build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe
@$(STAGE_ASSETS) -win-$(WINPLAT_X86)-Debug \ @$(STAGE_ASSETS) -win-$(WINPLAT_X86) -debug \
build/prefab/full/windows_x86_gui/debug build/prefab/full/windows_x86_gui/debug
build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe: .efrocachemap build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe: .efrocachemap
@ -506,7 +506,7 @@ prefab-windows-x86-gui-release: prefab-windows-x86-gui-release-build
prefab-windows-x86-gui-release-build: prereqs \ prefab-windows-x86-gui-release-build: prereqs \
assets-windows-$(WINPLAT_X86) \ assets-windows-$(WINPLAT_X86) \
build/prefab/full/windows_x86_gui/release/BallisticaKit.exe build/prefab/full/windows_x86_gui/release/BallisticaKit.exe
@$(STAGE_ASSETS) -win-$(WINPLAT_X86)-Release \ @$(STAGE_ASSETS) -win-$(WINPLAT_X86) -release \
build/prefab/full/windows_x86_gui/release build/prefab/full/windows_x86_gui/release
build/prefab/full/windows_x86_gui/release/BallisticaKit.exe: .efrocachemap build/prefab/full/windows_x86_gui/release/BallisticaKit.exe: .efrocachemap
@ -531,7 +531,7 @@ prefab-windows-x86-server-debug: prefab-windows-x86-server-debug-build
prefab-windows-x86-server-debug-build: prereqs \ prefab-windows-x86-server-debug-build: prereqs \
assets-windows-$(WINPLAT_X86) \ assets-windows-$(WINPLAT_X86) \
build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe
@$(STAGE_ASSETS) -winserver-$(WINPLAT_X86)-Debug \ @$(STAGE_ASSETS) -winserver-$(WINPLAT_X86) -debug \
build/prefab/full/windows_x86_server/debug build/prefab/full/windows_x86_server/debug
build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe: .efrocachemap build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe: .efrocachemap
@ -556,7 +556,7 @@ prefab-windows-x86-server-release: prefab-windows-x86-server-release-build
prefab-windows-x86-server-release-build: prereqs \ prefab-windows-x86-server-release-build: prereqs \
assets-windows-$(WINPLAT_X86) \ assets-windows-$(WINPLAT_X86) \
build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe
@$(STAGE_ASSETS) -winserver-$(WINPLAT_X86)-Release \ @$(STAGE_ASSETS) -winserver-$(WINPLAT_X86) -release \
build/prefab/full/windows_x86_server/release build/prefab/full/windows_x86_server/release
build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe: .efrocachemap build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe: .efrocachemap
@ -931,7 +931,7 @@ WINDOWS_CONFIGURATION ?= Debug
# Stage assets and other files so a built binary will run. # Stage assets and other files so a built binary will run.
windows-staging: assets-windows resources meta windows-staging: assets-windows resources meta
$(STAGE_ASSETS) -win-$(WINPLT)-$(WINCFG) \ $(STAGE_ASSETS) -win-$(WINPLT) -$(WINCFGLC) \
build/windows/$(WINCFG)_$(WINPLT) build/windows/$(WINCFG)_$(WINPLT)
# Build and run a debug windows build (from WSL). # Build and run a debug windows build (from WSL).
@ -1026,7 +1026,7 @@ cmake-lldb: cmake-build
# Build but don't run it. # Build but don't run it.
cmake-build: assets-cmake resources cmake-binary cmake-build: assets-cmake resources cmake-binary
@$(STAGE_ASSETS) -cmake build/cmake/$(CM_BT_LC) @$(STAGE_ASSETS) -cmake -$(CM_BT_LC) build/cmake/$(CM_BT_LC)
@tools/pcommand echo BLD Build complete: BLU build/cmake/$(CM_BT_LC) @tools/pcommand echo BLD Build complete: BLU build/cmake/$(CM_BT_LC)
cmake-binary: meta cmake-binary: meta
@ -1046,25 +1046,43 @@ cmake-server: cmake-server-build
cmake-server-build: assets-server meta cmake-server-binary cmake-server-build: assets-server meta cmake-server-binary
@$(STAGE_ASSETS) -cmakeserver -$(CM_BT_LC) build/cmake/server-$(CM_BT_LC) @$(STAGE_ASSETS) -cmakeserver -$(CM_BT_LC) build/cmake/server-$(CM_BT_LC)
@tools/pcommand echo BLD \ @tools/pcommand echo BLD \
Server build complete: BLU build/cmake/server-$(CM_BT_LC) Server build complete: BLU build/cmake/server-$(CM_BT_LC)
# Build just the headless binary.
# Note: We currently symlink FOO_headless. In packaged builds we rename it.
cmake-server-binary: meta cmake-server-binary: meta
@tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC)/dist @tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC)/dist
@cd build/cmake/server-$(CM_BT_LC)/dist && test -f Makefile \ @cd build/cmake/server-$(CM_BT_LC)/dist && test -f Makefile \
|| cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true \ || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true \
$(shell pwd)/ballisticakit-cmake $(shell pwd)/ballisticakit-cmake
@tools/pcommand update_cmake_prefab_lib server $(CM_BT_LC) build/cmake/server-$(CM_BT_LC)/dist @tools/pcommand update_cmake_prefab_lib server $(CM_BT_LC) build/cmake/server-$(CM_BT_LC)/dist
@cd build/cmake/server-$(CM_BT_LC)/dist && $(MAKE) -j$(CPUS) @cd build/cmake/server-$(CM_BT_LC)/dist && $(MAKE) -j$(CPUS) \
ballisticakit
cmake-server-clean: cmake-server-clean:
rm -rf build/cmake/server-$(CM_BT_LC) rm -rf build/cmake/server-$(CM_BT_LC)
cmake-modular-build: assets-cmake meta cmake-modular-binary
@$(STAGE_ASSETS) -cmakemodular -$(CM_BT_LC) \
build/cmake/modular-$(CM_BT_LC)/staged
@tools/pcommand echo BLD \
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
cmake-modular-binary: meta
@tools/pcommand cmake_prep_dir build/cmake/modular-$(CM_BT_LC)
@cd build/cmake/modular-$(CM_BT_LC) && test -f Makefile \
|| cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \
$(shell pwd)/ballisticakit-cmake
@cd build/cmake/modular-$(CM_BT_LC) && $(MAKE) -j$(CPUS) ballisticakitso
cmake-modular-clean:
rm -rf build/cmake/modular-$(CM_BT_LC)
# Stage assets for building/running within CLion. # Stage assets for building/running within CLion.
clion-staging: assets-cmake resources meta clion-staging: assets-cmake resources meta
$(STAGE_ASSETS) -cmake build/clion_debug $(STAGE_ASSETS) -cmake -debug build/clion_debug
$(STAGE_ASSETS) -cmake build/clion_release $(STAGE_ASSETS) -cmake -release build/clion_release
# Tell make which of these targets don't represent files. # Tell make which of these targets don't represent files.
.PHONY: cmake cmake-build cmake-clean cmake-server cmake-server-build \ .PHONY: cmake cmake-build cmake-clean cmake-server cmake-server-build \
@ -1162,6 +1180,7 @@ WIN_MSBUILD_EXE_B = "$(_WMSBE_1B)$(_WMSBE_2B)"
WINPRJ = $(WINDOWS_PROJECT) WINPRJ = $(WINDOWS_PROJECT)
WINPLT = $(WINDOWS_PLATFORM) WINPLT = $(WINDOWS_PLATFORM)
WINCFG = $(WINDOWS_CONFIGURATION) WINCFG = $(WINDOWS_CONFIGURATION)
WINCFGLC = $(shell echo $(WINDOWS_CONFIGURATION) | tr A-Z a-z)
# When using CLion, our cmake dir is root. Expose .clang-format there too. # When using CLion, our cmake dir is root. Expose .clang-format there too.
ballisticakit-cmake/.clang-format: .clang-format ballisticakit-cmake/.clang-format: .clang-format

View File

@ -137,6 +137,8 @@
<w>ballistica</w> <w>ballistica</w>
<w>ballistica's</w> <w>ballistica's</w>
<w>ballisticakit</w> <w>ballisticakit</w>
<w>ballisticakitso</w>
<w>ballisticaplus</w>
<w>bamasteraddr</w> <w>bamasteraddr</w>
<w>bamasterlegacy</w> <w>bamasterlegacy</w>
<w>bameta</w> <w>bameta</w>
@ -206,6 +208,7 @@
<w>bmas</w> <w>bmas</w>
<w>bmasl</w> <w>bmasl</w>
<w>bmcjphh</w> <w>bmcjphh</w>
<w>bmodfeaturesets</w>
<w>bname</w> <w>bname</w>
<w>bodyid</w> <w>bodyid</w>
<w>bodypart</w> <w>bodypart</w>
@ -324,6 +327,7 @@
<w>clipcount</w> <w>clipcount</w>
<w>cloudtoba</w> <w>cloudtoba</w>
<w>cmakelist</w> <w>cmakelist</w>
<w>cmakemodular</w>
<w>cmath</w> <w>cmath</w>
<w>cmds</w> <w>cmds</w>
<w>cmdspath</w> <w>cmdspath</w>
@ -454,6 +458,7 @@
<w>diesound</w> <w>diesound</w>
<w>diffbit</w> <w>diffbit</w>
<w>dinl</w> <w>dinl</w>
<w>dir's</w>
<w>dirfilter</w> <w>dirfilter</w>
<w>dirslash</w> <w>dirslash</w>
<w>displaytime</w> <w>displaytime</w>
@ -507,6 +512,7 @@
<w>dusing</w> <w>dusing</w>
<w>dval</w> <w>dval</w>
<w>dxgi</w> <w>dxgi</w>
<w>dylibdir</w>
<w>dynamicdata</w> <w>dynamicdata</w>
<w>echidna</w> <w>echidna</w>
<w>echofile</w> <w>echofile</w>
@ -539,6 +545,7 @@
<w>enumvalue</w> <w>enumvalue</w>
<w>enval</w> <w>enval</w>
<w>envcfg</w> <w>envcfg</w>
<w>envglobals</w>
<w>envs</w> <w>envs</w>
<w>envval</w> <w>envval</w>
<w>ericf</w> <w>ericf</w>
@ -558,6 +565,7 @@
<w>exargs</w> <w>exargs</w>
<w>exctype</w> <w>exctype</w>
<w>exec'ed</w> <w>exec'ed</w>
<w>exec'ing</w>
<w>execed</w> <w>execed</w>
<w>execinfo</w> <w>execinfo</w>
<w>execing</w> <w>execing</w>
@ -592,6 +600,7 @@
<w>fdata</w> <w>fdata</w>
<w>fdataraw</w> <w>fdataraw</w>
<w>fdcount</w> <w>fdcount</w>
<w>fdcwd</w>
<w>fdirs</w> <w>fdirs</w>
<w>fdirx</w> <w>fdirx</w>
<w>fdiry</w> <w>fdiry</w>
@ -660,6 +669,8 @@
<w>fsarg</w> <w>fsarg</w>
<w>fsconfigpath</w> <w>fsconfigpath</w>
<w>fset</w> <w>fset</w>
<w>fsetmfilenames</w>
<w>fsetmfilenamevals</w>
<w>fsetname</w> <w>fsetname</w>
<w>fsets</w> <w>fsets</w>
<w>fsmetapackagename</w> <w>fsmetapackagename</w>
@ -673,6 +684,7 @@
<w>ftos</w> <w>ftos</w>
<w>ftou</w> <w>ftou</w>
<w>fullpath</w> <w>fullpath</w>
<w>fullstr</w>
<w>funcname</w> <w>funcname</w>
<w>funcp</w> <w>funcp</w>
<w>fval</w> <w>fval</w>
@ -826,10 +838,12 @@
<w>inides</w> <w>inides</w>
<w>initguid</w> <w>initguid</w>
<w>initing</w> <w>initing</w>
<w>initname</w>
<w>inittab</w> <w>inittab</w>
<w>inputdevice</w> <w>inputdevice</w>
<w>inputter</w> <w>inputter</w>
<w>insta</w> <w>insta</w>
<w>instpath</w>
<w>intercollide</w> <w>intercollide</w>
<w>internalformat</w> <w>internalformat</w>
<w>internalmodule</w> <w>internalmodule</w>
@ -914,6 +928,7 @@
<w>lgui</w> <w>lgui</w>
<w>lhalf</w> <w>lhalf</w>
<w>libballistica</w> <w>libballistica</w>
<w>libballisticaplus</w>
<w>libbz</w> <w>libbz</w>
<w>libbzip</w> <w>libbzip</w>
<w>libfile</w> <w>libfile</w>
@ -998,6 +1013,7 @@
<w>maxtries</w> <w>maxtries</w>
<w>maxwait</w> <w>maxwait</w>
<w>maxwidth</w> <w>maxwidth</w>
<w>mbstowcs</w>
<w>mdpath</w> <w>mdpath</w>
<w>mediump</w> <w>mediump</w>
<w>memalign</w> <w>memalign</w>
@ -1014,6 +1030,7 @@
<w>metallink</w> <w>metallink</w>
<w>metamakefile</w> <w>metamakefile</w>
<w>meth</w> <w>meth</w>
<w>mfilename</w>
<w>mhbegin</w> <w>mhbegin</w>
<w>mhend</w> <w>mhend</w>
<w>microsecs</w> <w>microsecs</w>
@ -1164,6 +1181,7 @@
<w>olde</w> <w>olde</w>
<w>oldname</w> <w>oldname</w>
<w>oldpath</w> <w>oldpath</w>
<w>oldpaths</w>
<w>oldtoken</w> <w>oldtoken</w>
<w>olduuid</w> <w>olduuid</w>
<w>olduuids</w> <w>olduuids</w>
@ -1192,6 +1210,8 @@
<w>opposingbody</w> <w>opposingbody</w>
<w>opposingnode</w> <w>opposingnode</w>
<w>optin</w> <w>optin</w>
<w>optnm</w>
<w>optstuff</w>
<w>ortho</w> <w>ortho</w>
<w>osis</w> <w>osis</w>
<w>ossaudiodev</w> <w>ossaudiodev</w>
@ -1201,6 +1221,7 @@
<w>ourcode</w> <w>ourcode</w>
<w>ourname</w> <w>ourname</w>
<w>ourpackage</w> <w>ourpackage</w>
<w>ourpaths</w>
<w>ourself</w> <w>ourself</w>
<w>ourstanding</w> <w>ourstanding</w>
<w>outdict</w> <w>outdict</w>
@ -1223,6 +1244,7 @@
<w>pathbar</w> <w>pathbar</w>
<w>pathcapture</w> <w>pathcapture</w>
<w>pathdst</w> <w>pathdst</w>
<w>pathlen</w>
<w>pathlist</w> <w>pathlist</w>
<w>pathparts</w> <w>pathparts</w>
<w>pathsegs</w> <w>pathsegs</w>
@ -1362,6 +1384,8 @@
<w>pysitedir</w> <w>pysitedir</w>
<w>pythondevmode</w> <w>pythondevmode</w>
<w>pythonenumsmodule</w> <w>pythonenumsmodule</w>
<w>pythonoptimize</w>
<w>pythonutf</w>
<w>pytype</w> <w>pytype</w>
<w>qerr</w> <w>qerr</w>
<w>qrcode</w> <w>qrcode</w>
@ -1386,6 +1410,8 @@
<w>rdynamic</w> <w>rdynamic</w>
<w>reaaaly</w> <w>reaaaly</w>
<w>readexactly</w> <w>readexactly</w>
<w>readlink</w>
<w>readlinkat</w>
<w>readset</w> <w>readset</w>
<w>realloc</w> <w>realloc</w>
<w>reallocations</w> <w>reallocations</w>
@ -1579,6 +1605,7 @@
<w>sssssssi</w> <w>sssssssi</w>
<w>ssssssssssss</w> <w>ssssssssssss</w>
<w>ssval</w> <w>ssval</w>
<w>stager</w>
<w>standin</w> <w>standin</w>
<w>startedptr</w> <w>startedptr</w>
<w>startms</w> <w>startms</w>
@ -1635,6 +1662,7 @@
<w>swiftgeneratepch</w> <w>swiftgeneratepch</w>
<w>swiftmergegeneratedheaders</w> <w>swiftmergegeneratedheaders</w>
<w>symbolification</w> <w>symbolification</w>
<w>syscall</w>
<w>syscalls</w> <w>syscalls</w>
<w>sysresponse</w> <w>sysresponse</w>
<w>tabdefs</w> <w>tabdefs</w>
@ -1839,6 +1867,7 @@
<w>wiimote</w> <w>wiimote</w>
<w>wiimotes</w> <w>wiimotes</w>
<w>winapi</w> <w>winapi</w>
<w>wincfglc</w>
<w>windowshade</w> <w>windowshade</w>
<w>winmm</w> <w>winmm</w>
<w>winsock</w> <w>winsock</w>

View File

@ -177,6 +177,12 @@ add_library(ode
) )
target_include_directories(ode PRIVATE ${ODE_SRC_ROOT}) target_include_directories(ode PRIVATE ${ODE_SRC_ROOT})
# Necessary on GCC to allow linking in to our .so version.
# (but disabling semantic-interposition should lessen the associated speed hit).
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
target_compile_options(ode PRIVATE -fPIC -fno-semantic-interposition)
endif ()
# NOTE: There used to be an issue with optimized GCC builds where mesh # NOTE: There used to be an issue with optimized GCC builds where mesh
# collisions would fail randomly, leading to characters falling through # collisions would fail randomly, leading to characters falling through
# floors somewhat regularly. For this reason I was limiting optimization to # floors somewhat regularly. For this reason I was limiting optimization to
@ -194,8 +200,7 @@ target_include_directories(ode PRIVATE ${ODE_SRC_ROOT})
# endif() # endif()
# endif () # endif ()
# BallisticaKit binary. set(BALLISTICA_SOURCES
add_executable(ballisticakit
${BA_SRC_ROOT}/external/qr_code_generator/QrCode.cpp ${BA_SRC_ROOT}/external/qr_code_generator/QrCode.cpp
# AUTOGENERATED_PUBLIC_BEGIN (this section is managed by the "update_project" tool) # AUTOGENERATED_PUBLIC_BEGIN (this section is managed by the "update_project" tool)
${BA_SRC_ROOT}/ballistica/base/app/app.cc ${BA_SRC_ROOT}/ballistica/base/app/app.cc
@ -742,28 +747,65 @@ add_executable(ballisticakit
${BA_SRC_ROOT}/ballistica/ui_v1/widget/widget.cc ${BA_SRC_ROOT}/ballistica/ui_v1/widget/widget.cc
${BA_SRC_ROOT}/ballistica/ui_v1/widget/widget.h ${BA_SRC_ROOT}/ballistica/ui_v1/widget/widget.h
# AUTOGENERATED_PUBLIC_END # AUTOGENERATED_PUBLIC_END
) )
# BallisticaKit monolithic binary.
add_executable(ballisticakit ${BALLISTICA_SOURCES})
# Gets -rdynamic added when linking gcc builds which exports all symbols # Gets -rdynamic added when linking gcc builds which exports all symbols
# which gives us more meaningful stack traces using backtrace_symbols(). # which gives us more meaningful stack traces using backtrace_symbols().
set_target_properties(ballisticakit PROPERTIES ENABLE_EXPORTS 1) set_target_properties(ballisticakit PROPERTIES ENABLE_EXPORTS 1)
if (HEADLESS) if (HEADLESS)
set_target_properties(ballisticakit PROPERTIES OUTPUT_NAME "ballisticakit_headless") set_target_properties(ballisticakit
PROPERTIES OUTPUT_NAME "ballisticakit_headless")
endif () endif ()
target_include_directories(ballisticakit PRIVATE target_include_directories(ballisticakit PRIVATE
${Python_INCLUDE_DIRS} ${Python_INCLUDE_DIRS}
${BA_SRC_ROOT}/external/open_dynamics_engine-ef ${BA_SRC_ROOT}/external/open_dynamics_engine-ef
${EXTRA_INCLUDE_DIRS} ${EXTRA_INCLUDE_DIRS})
)
target_link_libraries(ballisticakit PRIVATE target_link_libraries(ballisticakit PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/prefablib/libballistica_plus.a ode pthread ${Python_LIBRARIES} ${CMAKE_CURRENT_BINARY_DIR}/prefablib/libballisticaplus.a ode pthread ${Python_LIBRARIES}
${SDL2_LIBRARIES} ${EXTRA_LIBRARIES} dl) ${SDL2_LIBRARIES} ${EXTRA_LIBRARIES} dl)
# Hack for building on rpi (might be due to my manually built Python 3.8) # Hack for building on rpi; need to update my pi so I can remove this.
# Hopefully can remove later...
if(EXISTS "/home/pi") if(EXISTS "/home/pi")
target_link_libraries(ballisticakit PRIVATE dl util stdc++fs) target_link_libraries(ballisticakit PRIVATE dl util stdc++fs)
endif() endif()
# BallisticaKit modular shared library
# (for use with vanilla Python interpreters).
add_library(ballisticakitso SHARED ${BALLISTICA_SOURCES})
# This is a 'modular' build.
target_compile_definitions(ballisticakitso PRIVATE BA_MONOLITHIC_BUILD=0)
# Gets -rdynamic added when linking gcc builds which exports all symbols
# which gives us more meaningful stack traces using backtrace_symbols().
set_target_properties(ballisticakitso PROPERTIES ENABLE_EXPORTS 1)
set_target_properties(ballisticakitso
PROPERTIES PREFIX "")
set_target_properties(ballisticakitso
PROPERTIES SUFFIX ".so")
if (HEADLESS)
set_target_properties(ballisticakitso
PROPERTIES OUTPUT_NAME "ballisticakit_headless")
else ()
set_target_properties(ballisticakitso
PROPERTIES OUTPUT_NAME "ballisticakit")
endif ()
target_include_directories(ballisticakitso PRIVATE
${Python_INCLUDE_DIRS}
${BA_SRC_ROOT}/external/open_dynamics_engine-ef
${EXTRA_INCLUDE_DIRS})
target_link_libraries(ballisticakitso PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/prefablib/libballisticaplus.a ode pthread ${Python_LIBRARIES}
${SDL2_LIBRARIES} ${EXTRA_LIBRARIES} dl)

View File

@ -14,7 +14,7 @@ fset = FeatureSet.get_active()
fset.requirements = set() fset.requirements = set()
fset.has_native_python_module = False fset.has_python_binary_module = False
# Bits of code we're using that don't conform to our feature-set based # Bits of code we're using that don't conform to our feature-set based
# namespace scheme. # namespace scheme.

View File

@ -12,6 +12,6 @@ from batools.featureset import FeatureSet
# Grab the FeatureSet we should apply to. # Grab the FeatureSet we should apply to.
fset = FeatureSet.get_active() fset = FeatureSet.get_active()
fset.has_native_python_module = False fset.has_python_binary_module = False
fset.requirements = {'core', 'base', 'scene_v1'} fset.requirements = {'core', 'base', 'scene_v1'}

View File

@ -12,6 +12,6 @@ from batools.featureset import FeatureSet
# Grab the FeatureSet we should apply to. # Grab the FeatureSet we should apply to.
fset = FeatureSet.get_active() fset = FeatureSet.get_active()
fset.has_native_python_module = False fset.has_python_binary_module = False
fset.requirements = {'core', 'base', 'ui_v1', 'classic'} fset.requirements = {'core', 'base', 'ui_v1', 'classic'}

View File

@ -54,8 +54,10 @@ def on_native_module_import() -> None:
# make noise if that's not the case. # make noise if that's not the case.
if debug_build != sys.flags.dev_mode: if debug_build != sys.flags.dev_mode:
logging.warning( logging.warning(
'Mismatch in ballistica debug_build %s' 'Ballistica was built with debug-mode %s'
' and sys.flags.dev_mode %s; this may cause problems.', ' but Python is running with dev-mode %s;'
' this mismatch may cause problems.'
' See https://docs.python.org/3/library/devmode.html',
debug_build, debug_build,
sys.flags.dev_mode, sys.flags.dev_mode,
) )
@ -75,11 +77,11 @@ def setup_env_for_app_run() -> None:
assert baenv.config_exists() assert baenv.config_exists()
# If we were unable to set paths earlier, complain now. # If we were unable to set paths earlier, complain now.
if baenv.g_paths_set_failed: if baenv.did_paths_set_fail():
logging.warning( logging.warning(
'Ballistica Python paths have not been set. This may cause' 'Ballistica Python paths have not been set. This may cause'
' problems. To ensure paths are set, run baenv.configure()' ' problems. To ensure paths are set, run baenv.configure()'
' before importing any ballistica modules.' ' BEFORE importing any Ballistica modules.'
) )
# Set up interrupt-signal handling. # Set up interrupt-signal handling.
@ -144,9 +146,10 @@ def on_app_launching() -> None:
assert _babase.in_logic_thread() assert _babase.in_logic_thread()
# Let the user know if the app python dir is a custom one. # Let the user know if the app python dir is a custom one.
if baenv.g_user_system_scripts_dir is not None: user_sys_scripts_dir = baenv.get_user_system_scripts_dir()
if user_sys_scripts_dir is not None:
_babase.screenmessage( _babase.screenmessage(
f"Using user system scripts: '{baenv.g_user_system_scripts_dir}'", f"Using user system scripts: '{user_sys_scripts_dir}'",
color=(0.6, 0.6, 1.0), color=(0.6, 0.6, 1.0),
) )

View File

@ -267,6 +267,9 @@ class StoreSubsystem:
'icons.mikirog': { 'icons.mikirog': {
'icon': babase.charstr(babase.SpecialChar.MIKIROG) 'icon': babase.charstr(babase.SpecialChar.MIKIROG)
}, },
'icons.explodinary': {
'icon': babase.charstr(babase.SpecialChar.EXPLODINARY_LOGO)
},
} }
return babase.app.classic.store_items return babase.app.classic.store_items

View File

@ -4,9 +4,11 @@
This module is used to set up and/or check the global Python environment This module is used to set up and/or check the global Python environment
before running a ballistica app. This includes things such as paths, before running a ballistica app. This includes things such as paths,
logging, debug-modes, garbage-collection settings, and signal handling. logging, and app-dirs. Because these things are global in nature, this
Because these things are global in nature, this should be done before should be done before any ballistica modules are imported.
any ballistica modules are imported.
This module can also be exec'ed directly to set up a default environment
and then run the app.
Ballistica can be used without explicitly configuring the environment in Ballistica can be used without explicitly configuring the environment in
order to integrate it in arbitrary Python environments, but this may order to integrate it in arbitrary Python environments, but this may
@ -20,25 +22,42 @@ import logging
from pathlib import Path from pathlib import Path
from dataclasses import dataclass from dataclasses import dataclass
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import __main__
from efro.log import setup_logging, LogLevel from efro.log import setup_logging, LogLevel
if TYPE_CHECKING: if TYPE_CHECKING:
from efro.log import LogHandler from efro.log import LogHandler
# IMPORTANT - It is likely (and in some cases expected) that this
# 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
# /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.
#
# So we need to do a few things to handle that situation gracefully.
#
# - First, we need to store any mutable global state in the __main__
# module; not in ourself. This way, alternate versions of ourself will
# still know if we already ran configure/etc.
#
# - Second, we should avoid the use of isinstance and similar calls for
# our types. An EnvConfig we create would technically be a different
# type than that created by an alternate baenv.
# Build number and version of the ballistica binary we expect to be # Build number and version of the ballistica binary we expect to be
# using. # using.
TARGET_BALLISTICA_BUILD = 21171 TARGET_BALLISTICA_BUILD = 21183
TARGET_BALLISTICA_VERSION = '1.7.23' TARGET_BALLISTICA_VERSION = '1.7.24'
_g_env_config: EnvConfig | None = None
g_paths_set_failed = False # pylint: disable=invalid-name
g_user_system_scripts_dir: str | None = None
@dataclass @dataclass
class EnvConfig: class EnvConfig:
"""Final settings put together by the configure call.""" """Environment put together by the configure call."""
config_dir: str config_dir: str
data_dir: str data_dir: str
@ -49,17 +68,56 @@ class EnvConfig:
log_handler: LogHandler | None log_handler: LogHandler | None
@dataclass
class EnvGlobals:
"""Our globals we store in the main module."""
config: EnvConfig | None = None
config_called: bool = False
paths_set_failed: bool = False
user_system_scripts_dir: str | None = None
@classmethod
def get(cls) -> EnvGlobals:
"""Create/return our singleton."""
name = '_baenv_globals'
envglobals: EnvGlobals | None = getattr(__main__, name, None)
if envglobals is None:
envglobals = EnvGlobals()
setattr(__main__, name, envglobals)
return envglobals
def config_exists() -> bool: def config_exists() -> bool:
"""Has a config been created?""" """Has a config been created?"""
return _g_env_config is not None
return EnvGlobals.get().config is not None
def did_paths_set_fail() -> bool:
"""Did we try to set paths and failed?"""
return EnvGlobals.get().paths_set_failed
def get_user_system_scripts_dir() -> str | None:
"""If there's a custom user system scripts dir in play, return it."""
return EnvGlobals.get().user_system_scripts_dir
def get_config() -> EnvConfig: def get_config() -> EnvConfig:
"""Return the active env-config. Creates default if none exists.""" """Return the active config, creating a default if none exists."""
if _g_env_config is None: envglobals = EnvGlobals.get()
if not envglobals.config_called:
configure() configure()
assert _g_env_config is not None
return _g_env_config config = envglobals.config
if config is None:
raise RuntimeError(
'baenv.configure() has been called but no config exists;'
' perhaps it errored?'
)
return config
def configure( def configure(
@ -72,22 +130,91 @@ def configure(
) -> None: ) -> None:
"""Set up the Python environment for running a ballistica app. """Set up the Python environment for running a ballistica app.
This includes things such as Python paths and log redirection. For This includes things such as Python path wrangling and app directory
that reason, this should be called before any other ballistica creation. This should be called before any other ballistica modules
modules are imported, since it may make changes to sys.path, are imported since it may make changes to sys.path which can affect
affecting where those modules get loaded from. where those modules get loaded from.
""" """
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
global _g_env_config # pylint: disable=global-statement envglobals = EnvGlobals.get()
if _g_env_config is not None:
raise RuntimeError('An EnvConfig has already been created.')
# The very first thing we do is set up our logging system and feed if envglobals.config_called:
# Python's stdout/stderr into it. Then we can at least debug problems raise RuntimeError(
# on systems where native stdout/stderr is not easily accessible 'baenv.configure() has already been called;'
# such as Android. ' it can only be called once.'
)
envglobals.config_called = 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
# problems on systems where native stdout/stderr is not easily
# accessible such as Android.
log_handler = _setup_logging()
# We want to always be run in UTF-8 mode; complain if we're not.
if sys.flags.utf8_mode != 1:
logging.warning(
"Python's UTF-8 mode is not set. Running ballistica without"
' it may lead to errors.'
)
# Attempt to set up Python paths and our own data paths so that
# engine modules, mods, etc. are pulled from predictable places.
(
user_python_dir,
app_python_dir,
site_python_dir,
data_dir,
config_dir,
standard_app_python_dir,
) = _setup_paths(
user_python_dir,
app_python_dir,
site_python_dir,
data_dir,
config_dir,
)
# Attempt to create dirs that we'll write stuff to.
_setup_dirs(config_dir, user_python_dir)
# Get ssl working if needed so we can use https and all that.
_setup_certs(contains_python_dist)
# This is now the active config.
envglobals.config = EnvConfig(
config_dir=config_dir,
data_dir=data_dir,
user_python_dir=user_python_dir,
app_python_dir=app_python_dir,
standard_app_python_dir=standard_app_python_dir,
site_python_dir=site_python_dir,
log_handler=log_handler,
)
def _calc_data_dir(data_dir: str | None) -> str:
if data_dir is None:
# To calc default data_dir, we assume this module was imported
# from that dir's ba_data/python subdir.
assert Path(__file__).parts[-3:-1] == ('ba_data', 'python')
data_dir_path = Path(__file__).parents[2]
# Prefer tidy relative paths like '.' if possible so that things
# like stack traces are easier to read.
# NOTE: Perhaps we should have an option to disable this
# behavior for cases where the user might be doing chdir stuff.
cwd_path = Path.cwd()
data_dir = str(
data_dir_path.relative_to(cwd_path)
if data_dir_path.is_relative_to(cwd_path)
else data_dir_path
)
return data_dir
def _setup_logging() -> LogHandler:
log_handler = setup_logging( log_handler = setup_logging(
log_path=None, log_path=None,
level=LogLevel.DEBUG, level=LogLevel.DEBUG,
@ -95,41 +222,46 @@ def configure(
log_stdout_stderr=True, log_stdout_stderr=True,
cache_size_limit=1024 * 1024, cache_size_limit=1024 * 1024,
) )
return log_handler
# Sanity check: we should always be run in UTF-8 mode.
if sys.flags.utf8_mode != 1:
logging.warning(
"Python's UTF-8 mode is not set. Running ballistica without"
' it may lead to errors.'
)
# Now do paths. We want to set stuff up so that engine modules, def _setup_certs(contains_python_dist: bool) -> None:
# mods, etc. are pulled from predictable places. # In situations where we're bringing our own Python let's also
cwd_path = Path.cwd() # provide our own root certs so ssl works. We can consider
# overriding this in particular embedded cases if we can verify that
# system certs are working. We also allow forcing this via an env
# var if the user desires.
if (
contains_python_dist
or os.environ.get('BA_USE_BUNDLED_ROOT_CERTS') == '1'
):
import certifi
# A few paths we can ALWAYS calculate since they don't affect Python # Let both OpenSSL and requests (if present) know to use this.
# imports: os.environ['SSL_CERT_FILE'] = os.environ[
'REQUESTS_CA_BUNDLE'
] = certifi.where()
# Default data_dir assumes this module was imported from its
# ba_data/python subdir. def _setup_paths(
if data_dir is None: user_python_dir: str | None,
assert Path(__file__).parts[-3:-1] == ('ba_data', 'python') app_python_dir: str | None,
data_dir_path = Path(__file__).parents[2] site_python_dir: str | None,
# Prefer tidy relative paths like '.' if possible. data_dir: str | None,
data_dir = str( config_dir: str | None,
data_dir_path.relative_to(cwd_path) ) -> tuple[str | None, str | None, str | None, str, str, str]:
if data_dir_path.is_relative_to(cwd_path) # First a few paths we can ALWAYS calculate since they don't affect
else data_dir_path # Python imports:
)
envglobals = EnvGlobals.get()
data_dir = _calc_data_dir(data_dir)
# Default config-dir is simply ~/.ballisticakit # Default config-dir is simply ~/.ballisticakit
if config_dir is None: if config_dir is None:
config_dir = str(Path(Path.home(), '.ballisticakit')) config_dir = str(Path(Path.home(), '.ballisticakit'))
# Ok now Python paths. # Standard app-python-dir is simply ba_data/python under data-dir.
# By default, app-python-dir is simply ba_data/python under
# data-dir.
standard_app_python_dir = str(Path(data_dir, 'ba_data', 'python')) standard_app_python_dir = str(Path(data_dir, 'ba_data', 'python'))
# If _babase has already been imported, there's not much we can do # If _babase has already been imported, there's not much we can do
@ -137,12 +269,11 @@ def configure(
if '_babase' in sys.modules: if '_babase' in sys.modules:
app_python_dir = user_python_dir = site_python_dir = None app_python_dir = user_python_dir = site_python_dir = None
# We don't actually complain yet here; we simply take note # We don't actually complain yet here; we simply take note that
# that we weren't able to set paths. Then we complain if/when # we weren't able to set paths. Then we complain if/when the app
# the app is started. This way, non-app uses of babase won't be # is started. This way, non-app uses of babase won't be filled
# filled with unnecessary warnings. # with unnecessary warnings.
global g_paths_set_failed # pylint: disable=global-statement envglobals.paths_set_failed = True
g_paths_set_failed = True
else: else:
# Ok; _babase hasn't been imported yet so we can muck with # Ok; _babase hasn't been imported yet so we can muck with
@ -163,35 +294,58 @@ def configure(
# Wherever our user_python_dir is, if we find a sys/FOO dir # Wherever our user_python_dir is, if we find a sys/FOO dir
# under it where FOO matches our version, use that as our # under it where FOO matches our version, use that as our
# app_python_dir. # app_python_dir. This allows modding built-in stuff on
check_dir = os.path.join( # platforms where there is no write access to said built-in
user_python_dir, 'sys', TARGET_BALLISTICA_VERSION # stuff.
) check_dir = Path(user_python_dir, 'sys', TARGET_BALLISTICA_VERSION)
if os.path.isdir(check_dir): if check_dir.is_dir():
global g_user_system_scripts_dir # pylint: disable=global-statement envglobals.user_system_scripts_dir = app_python_dir = str(check_dir)
g_user_system_scripts_dir = check_dir
app_python_dir = check_dir
# Ok, now apply these to sys.path. # Ok, now apply these to sys.path.
# First off, strip out any instances of the path containing this # First off, strip out any instances of the path containing this
# module. We will probably be re-adding the same path in a # module. We will *probably* be re-adding the same path in a
# moment but its technically possible that we won't be (if # moment so this keeps things cleaner. Though hmm should we
# app_python_dir is overridden to somewhere else, etc.) # leave it in there in cases where we *don't* re-add the same
# path?...
our_parent_path = Path(__file__).parent.resolve() our_parent_path = Path(__file__).parent.resolve()
paths: list[str] = [ oldpaths: list[str] = [
p for p in sys.path if Path(p).resolve() != our_parent_path p for p in sys.path if Path(p).resolve() != our_parent_path
] ]
# Let's lookup mods first (so users can do whatever they want).
# and then our bundled scripts last (don't want bundled
# site-package stuff overwriting system versions)
paths.insert(0, user_python_dir)
paths.append(app_python_dir)
paths.append(site_python_dir)
sys.path = paths
# Attempt to create the dirs that we'll write stuff to. Not the end # Let's place mods first (so users can override whatever they
# of the world if we fail though. # want) followed by our app scripts and lastly our bundled site
# stuff.
# One could make the argument that at least our bundled app &
# site stuff should be placed at the end so actual local site
# stuff could override it. That could be a good thing or a bad
# thing. Maybe we could add an option for that, but for now I'm
# prioritizing our stuff to give as consistent an environment as
# possible.
ourpaths = [user_python_dir, app_python_dir, site_python_dir]
# Special case: our modular builds will have a 'python-dylib'
# dir alongside the 'python' scripts dir which contains our
# binary Python modules. If we see that, add it to the path also.
# Not sure if we'd ever have a need to customize this path.
dylibdir = f'{app_python_dir}-dylib'
if os.path.exists(dylibdir):
ourpaths.append(dylibdir)
sys.path = ourpaths + oldpaths
return (
user_python_dir,
app_python_dir,
site_python_dir,
data_dir,
config_dir,
standard_app_python_dir,
)
def _setup_dirs(config_dir: str | None, user_python_dir: str | None) -> None:
create_dirs: list[tuple[str, str | None]] = [ create_dirs: list[tuple[str, str | None]] = [
('config', config_dir), ('config', config_dir),
('user_python', user_python_dir), ('user_python', user_python_dir),
@ -201,32 +355,22 @@ def configure(
try: try:
os.makedirs(cdir, exist_ok=True) os.makedirs(cdir, exist_ok=True)
except Exception: except Exception:
# Not the end of the world if we can't make these dirs.
logging.warning( logging.warning(
"Unable to create %s dir at '%s'.", cdirname, cdir "Unable to create %s dir at '%s'.", cdirname, cdir
) )
_g_env_config = EnvConfig(
config_dir=config_dir,
data_dir=data_dir,
user_python_dir=user_python_dir,
app_python_dir=app_python_dir,
standard_app_python_dir=standard_app_python_dir,
site_python_dir=site_python_dir,
log_handler=log_handler,
)
# In embedded situations (when we're providing our own Python) let's def _main() -> None:
# also provide our own root certs so ssl works. We can consider # Run a default configure BEFORE importing babase.
# overriding this in particular embedded cases if we can verify that # (may affect where babase comes from).
# system certs are working. (We also allow forcing this via an env configure()
# var if the user desires)
if (
contains_python_dist
or os.environ.get('BA_USE_BUNDLED_ROOT_CERTS') == '1'
):
import certifi
# Let both OpenSSL and requests (if present) know to use this. import babase
os.environ['SSL_CERT_FILE'] = os.environ[
'REQUESTS_CA_BUNDLE' babase.app.run()
] = certifi.where()
# Allow exec'ing this module directly to do a standard app run.
if __name__ == '__main__':
_main()

View File

@ -177,6 +177,11 @@ void BaseFeatureSet::StartApp() {
LogVersionInfo(); LogVersionInfo();
// The logic thread (or maybe other things) need to run Python as
// we're bringing them up, so let it go for the duration of this call.
// We'll explicitly grab it if/when we need it.
Python::ScopedInterpreterLockRelease gil_release;
// Read in ba.app.config for anyone who wants to start looking at it // Read in ba.app.config for anyone who wants to start looking at it
// (though we don't explicitly ask anyone to apply it until later). // (though we don't explicitly ask anyone to apply it until later).
python->ReadConfig(); python->ReadConfig();
@ -280,6 +285,10 @@ void BaseFeatureSet::RunAppToCompletion() {
StartApp(); StartApp();
} }
// Let go of the GIL while we're running. The logic thread or other things
// will grab it when needed.
Python::ScopedInterpreterLockRelease gil_release;
// On our event-loop-managing platforms we now simply sit in our event // On our event-loop-managing platforms we now simply sit in our event
// loop until the app is quit. // loop until the app is quit.
g_core->main_event_loop()->RunEventLoop(false); g_core->main_event_loop()->RunEventLoop(false);
@ -494,8 +503,13 @@ void BaseFeatureSet::DoV1CloudLog(const std::string& msg) {
// We may attempt to import stuff and that should *never* happen before // We may attempt to import stuff and that should *never* happen before
// base is fully imported. // base is fully imported.
if (!IsBaseCompletelyImported()) { if (!IsBaseCompletelyImported()) {
printf( static bool warned = false;
"WARNING: V1CloudLog called before babase fully imported; ignoring.\n"); if (!warned) {
warned = true;
printf(
"WARNING: V1CloudLog called before babase fully imported; "
"ignoring.\n");
}
return; return;
} }
@ -523,7 +537,11 @@ void BaseFeatureSet::DoV1CloudLog(const std::string& msg) {
// Need plus for direct sends. // Need plus for direct sends.
if (!HavePlus()) { if (!HavePlus()) {
printf("WARNING: V1CloudLog direct-sends not available; ignoring.\n"); static bool did_warn = false;
if (!did_warn) {
did_warn = true;
printf("WARNING: V1CloudLog direct-sends not available; ignoring.\n");
}
return; return;
} }

View File

@ -49,8 +49,6 @@ static PyMethodDef PyAppNameDef = {
static auto PyRunApp(PyObject* self) -> PyObject* { static auto PyRunApp(PyObject* self) -> PyObject* {
BA_PYTHON_TRY; BA_PYTHON_TRY;
FatalError("NOT WORKING YET; COME BACK SOON.");
assert(g_base); assert(g_base);
g_base->RunAppToCompletion(); g_base->RunAppToCompletion();

View File

@ -97,7 +97,7 @@ void CoreFeatureSet::PostInit() {
// FIXME: MOVE THIS TO A RUN_APP_TO_COMPLETION() SORT OF PLACE. // 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 // 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. // builds but this will need to account for more situations later.
python->ReleaseMainThreadGIL(); // python->ReleaseMainThreadGIL();
} }
auto CoreFeatureSet::CalcBuildSrcDir() -> std::string { auto CoreFeatureSet::CalcBuildSrcDir() -> std::string {

View File

@ -202,14 +202,6 @@ void CorePython::ImportPythonObjs() {
} }
} }
void CorePython::ReleaseMainThreadGIL() {
assert(g_core->InMainThread());
// After we bootstrap Python here in the main thread we release the GIL.
// We'll explicitly reacquire it anytime we need it (mainly in the logic
// thread once that comes up later).
PyEval_SaveThread();
}
void CorePython::SoftImportBase() { void CorePython::SoftImportBase() {
auto gil{Python::ScopedInterpreterLock()}; auto gil{Python::ScopedInterpreterLock()};
auto result = PythonRef::StolenSoft(PyImport_ImportModule("_babase")); auto result = PythonRef::StolenSoft(PyImport_ImportModule("_babase"));
@ -345,29 +337,4 @@ void CorePython::LoggingCall(LogLevel loglevel, const std::string& msg) {
objs().Get(logcallobj).Call(args); objs().Get(logcallobj).Call(args);
} }
void CorePython::AcquireGIL() {
assert(g_base_soft && g_base_soft->InLogicThread());
auto debug_timing{g_core->core_config().debug_timing};
millisecs_t startms{debug_timing ? CorePlatform::GetCurrentMillisecs() : 0};
if (logic_thread_state_) {
PyEval_RestoreThread(logic_thread_state_);
logic_thread_state_ = nullptr;
}
if (debug_timing) {
auto duration{CorePlatform::GetCurrentMillisecs() - startms};
if (duration > (1000 / 120)) {
Log(LogLevel::kInfo,
"GIL acquire took too long (" + std::to_string(duration) + " ms).");
}
}
}
void CorePython::ReleaseGIL() {
assert(g_base_soft && g_base_soft->InLogicThread());
assert(logic_thread_state_ == nullptr);
logic_thread_state_ = PyEval_SaveThread();
}
} // namespace ballistica::core } // namespace ballistica::core

View File

@ -52,11 +52,8 @@ class CorePython {
/// logging is available, logs locally using Logging::DisplayLog() /// logging is available, logs locally using Logging::DisplayLog()
/// (with an added warning). /// (with an added warning).
void LoggingCall(LogLevel loglevel, const std::string& msg); void LoggingCall(LogLevel loglevel, const std::string& msg);
void AcquireGIL();
void ReleaseGIL();
void ImportPythonObjs(); void ImportPythonObjs();
void VerifyPythonEnvironment(); void VerifyPythonEnvironment();
void ReleaseMainThreadGIL();
void SoftImportBase(); void SoftImportBase();
const auto& objs() { return objs_; } const auto& objs() { return objs_; }
@ -64,8 +61,6 @@ class CorePython {
private: private:
PythonObjectSet<ObjID> objs_; PythonObjectSet<ObjID> objs_;
PyThreadState* logic_thread_state_{};
// Log calls we make before we're set up to ship logs through Python // Log calls we make before we're set up to ship logs through Python
// go here. They all get shipped at once as soon as it is possible. // go here. They all get shipped at once as soon as it is possible.
bool python_logging_calls_enabled_{}; bool python_logging_calls_enabled_{};

View File

@ -2,5 +2,5 @@
Bits of the engine related to accounts and cloud functionality. In prefab builds Bits of the engine related to accounts and cloud functionality. In prefab builds
the compiled code for this feature set is contained in the pre-compiled static the compiled code for this feature set is contained in the pre-compiled static
ballistica_plus library. The plus feature set can also be removed from ballisticaplus library. The plus feature set can also be removed from
spinoff projects if desired to remove the need for that library. spinoff projects if desired to remove the need for that library.

View File

@ -385,16 +385,18 @@ void ConnectionToClient::HandleMessagePacket(
case BA_MESSAGE_CLIENT_INFO: { case BA_MESSAGE_CLIENT_INFO: {
if (buffer.size() > 1) { if (buffer.size() > 1) {
// Make a null-terminated copy of the string data.
std::vector<char> str_buffer(buffer.size()); std::vector<char> str_buffer(buffer.size());
memcpy(&(str_buffer[0]), &(buffer[1]), buffer.size() - 1); memcpy(str_buffer.data(), buffer.data() + 1, buffer.size() - 1);
str_buffer[str_buffer.size() - 1] = 0; str_buffer[str_buffer.size() - 1] = 0;
cJSON* info = cJSON_Parse(reinterpret_cast<const char*>(&(buffer[1])));
cJSON* info = cJSON_Parse(str_buffer.data());
if (info) { if (info) {
cJSON* b = cJSON_GetObjectItem(info, "b"); cJSON* b = cJSON_GetObjectItem(info, "b");
if (b) { if (b) {
build_number_ = b->valueint; build_number_ = b->valueint;
} else { } else {
Log(LogLevel::kError, "no buildnumber in clientinfo msg"); Log(LogLevel::kError, "No buildnumber in clientinfo msg.");
} }
// Grab their token (we use this to ask the // Grab their token (we use this to ask the
@ -403,7 +405,7 @@ void ConnectionToClient::HandleMessagePacket(
if (t) { if (t) {
token_ = t->valuestring; token_ = t->valuestring;
} else { } else {
Log(LogLevel::kError, "no token in clientinfo msg"); Log(LogLevel::kError, "No token in clientinfo msg.");
} }
// Newer clients also pass a peer-hash, which // Newer clients also pass a peer-hash, which
@ -423,9 +425,9 @@ void ConnectionToClient::HandleMessagePacket(
cJSON_Delete(info); cJSON_Delete(info);
} else { } else {
Log(LogLevel::kError, Log(LogLevel::kError,
"got invalid json in clientinfo message: '" "Got invalid json in clientinfo message: '"
+ std::string(reinterpret_cast<const char*>(&(buffer[1]))) + std::string(reinterpret_cast<const char*>(&(buffer[1])))
+ "'"); + "'.");
} }
} }
got_client_info_ = true; got_client_info_ = true;

View File

@ -22,7 +22,7 @@
#endif #endif
// If desired, define main() in the global namespace. // If desired, define main() in the global namespace.
#if BA_DEFINE_MAIN #if BA_MONOLITHIC_BUILD && BA_DEFINE_MAIN
auto main(int argc, char** argv) -> int { auto main(int argc, char** argv) -> int {
auto core_config = auto core_config =
ballistica::core::CoreConfig::FromCommandLineAndEnv(argc, argv); ballistica::core::CoreConfig::FromCommandLineAndEnv(argc, argv);
@ -39,8 +39,10 @@ auto main(int argc, char** argv) -> int {
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't modify them here. // These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 21171; const int kEngineBuildNumber = 21183;
const char* kEngineVersion = "1.7.23"; const char* kEngineVersion = "1.7.24";
#if BA_MONOLITHIC_BUILD
auto MonolithicMain(const core::CoreConfig& core_config) -> int { auto MonolithicMain(const core::CoreConfig& core_config) -> int {
// This code is meant to be run standalone so won't inherit any // This code is meant to be run standalone so won't inherit any
@ -171,6 +173,8 @@ auto MonolithicMain(const core::CoreConfig& core_config) -> int {
return -1; // Didn't even get core; something clearly wrong. return -1; // Didn't even get core; something clearly wrong.
} }
#endif // BA_MONOLITHIC_BUILD
void FatalError(const std::string& message) { void FatalError(const std::string& message) {
// Let the user and/or master-server know we're dying. // Let the user and/or master-server know we're dying.
FatalError::ReportFatalError(message, false); FatalError::ReportFatalError(message, false);

View File

@ -104,8 +104,10 @@ class CoreConfig;
// enough that avoiding the extra class includes seems like an overall // enough that avoiding the extra class includes seems like an overall
// compile-time/convenience win. // compile-time/convenience win.
#if BA_MONOLITHIC_BUILD
/// Entry point for standard monolithic builds. Handles all initing and running. /// Entry point for standard monolithic builds. Handles all initing and running.
auto MonolithicMain(const core::CoreConfig& config) -> int; auto MonolithicMain(const core::CoreConfig& config) -> int;
#endif // BA_MONOLITHIC_BUILD
// Print a momentary message on the screen. // Print a momentary message on the screen.
void ScreenMessage(const std::string& msg); void ScreenMessage(const std::string& msg);

View File

@ -64,7 +64,9 @@
// Allow stdin commands too. // Allow stdin commands too.
#define BA_ENABLE_STDIO_CONSOLE 1 #define BA_ENABLE_STDIO_CONSOLE 1
#ifndef BA_DEFINE_MAIN
#define BA_DEFINE_MAIN 1 #define BA_DEFINE_MAIN 1
#endif
#if !BA_DEBUG_BUILD #if !BA_DEBUG_BUILD

View File

@ -23,8 +23,10 @@ namespace ballistica {
// can override any of these before this is included. // can override any of these before this is included.
// Monolithic builds consist of a single binary that inits and manages // Monolithic builds consist of a single binary that inits and manages
// Python itself, as opposed to modular builds which are made up of // Python itself, as opposed to modular builds which are made up of Python
// Python binary modules which are run under a standard Python runtime. // binary modules which are run under a standard Python runtime. This will
// be 0 for both modular (.so) builds of the engine as well as for static
// libraries such as baplus intended to be linked to either version.
#ifndef BA_MONOLITHIC_BUILD #ifndef BA_MONOLITHIC_BUILD
#define BA_MONOLITHIC_BUILD 1 #define BA_MONOLITHIC_BUILD 1
#endif #endif

View File

@ -7,6 +7,7 @@
#include "ballistica/core/support/base_soft.h" #include "ballistica/core/support/base_soft.h"
#include "ballistica/shared/foundation/fatal_error.h" #include "ballistica/shared/foundation/fatal_error.h"
#include "ballistica/shared/python/python.h" #include "ballistica/shared/python/python.h"
#include "ballistica/shared/python/python_sys.h"
namespace ballistica { namespace ballistica {
@ -224,7 +225,7 @@ void EventLoop::WaitForNextEvent(bool single_cycle) {
// While we're waiting, allow other python threads to run. // While we're waiting, allow other python threads to run.
if (acquires_python_gil_) { if (acquires_python_gil_) {
g_core->python->ReleaseGIL(); ReleaseGIL();
} }
// If we've got active timers, wait for messages with a timeout so we can // If we've got active timers, wait for messages with a timeout so we can
@ -257,7 +258,7 @@ void EventLoop::WaitForNextEvent(bool single_cycle) {
} }
if (acquires_python_gil_) { if (acquires_python_gil_) {
g_core->python->AcquireGIL(); AcquireGIL();
} }
} }
@ -451,7 +452,7 @@ void EventLoop::SetAcquiresPythonGIL() {
assert(!acquires_python_gil_); // This should be called exactly once. assert(!acquires_python_gil_); // This should be called exactly once.
assert(ThreadIsCurrent()); assert(ThreadIsCurrent());
acquires_python_gil_ = true; acquires_python_gil_ = true;
g_core->python->AcquireGIL(); AcquireGIL();
} }
// Explicitly kill the main thread. // Explicitly kill the main thread.
@ -784,4 +785,30 @@ auto EventLoop::CheckPushRunnableSafety() -> bool {
return thread_messages_.size() < kThreadMessageSafetyThreshold; return thread_messages_.size() < kThreadMessageSafetyThreshold;
} }
void EventLoop::AcquireGIL() {
assert(g_base_soft && g_base_soft->InLogicThread());
auto debug_timing{g_core->core_config().debug_timing};
millisecs_t startms{debug_timing ? core::CorePlatform::GetCurrentMillisecs()
: 0};
if (py_thread_state_) {
PyEval_RestoreThread(py_thread_state_);
py_thread_state_ = nullptr;
}
if (debug_timing) {
auto duration{core::CorePlatform::GetCurrentMillisecs() - startms};
if (duration > (1000 / 120)) {
Log(LogLevel::kInfo,
"GIL acquire took too long (" + std::to_string(duration) + " ms).");
}
}
}
void EventLoop::ReleaseGIL() {
assert(g_base_soft && g_base_soft->InLogicThread());
assert(py_thread_state_ == nullptr);
py_thread_state_ = PyEval_SaveThread();
}
} // namespace ballistica } // namespace ballistica

View File

@ -164,6 +164,9 @@ class EventLoop {
void RunPauseCallbacks(); void RunPauseCallbacks();
void RunResumeCallbacks(); void RunResumeCallbacks();
void AcquireGIL();
void ReleaseGIL();
bool bootstrapped_{}; bool bootstrapped_{};
std::list<std::pair<Runnable*, bool*>> runnables_; std::list<std::pair<Runnable*, bool*>> runnables_;
std::list<Runnable*> pause_callbacks_; std::list<Runnable*> pause_callbacks_;
@ -174,6 +177,7 @@ class EventLoop {
std::condition_variable client_listener_cv_; std::condition_variable client_listener_cv_;
std::mutex client_listener_mutex_; std::mutex client_listener_mutex_;
std::list<std::vector<char>> data_to_client_; std::list<std::vector<char>> data_to_client_;
PyThreadState* py_thread_state_{};
TimerList timers_; TimerList timers_;
}; };

View File

@ -377,21 +377,16 @@ void Python::MarkReachedEndOfModule(PyObject* module) {
class Python::ScopedInterpreterLock::Impl { class Python::ScopedInterpreterLock::Impl {
public: public:
Impl() { Impl() {
if (need_lock_) { // Grab the python GIL.
// Grab the python GIL. gil_state_ = PyGILState_Ensure();
gstate_ = PyGILState_Ensure();
}
} }
~Impl() { ~Impl() {
if (need_lock_) { // Release the python GIL.
// Release the python GIL. PyGILState_Release(gil_state_);
PyGILState_Release(gstate_);
}
} }
private: private:
bool need_lock_{true}; PyGILState_STATE gil_state_{PyGILState_UNLOCKED};
PyGILState_STATE gstate_{PyGILState_UNLOCKED};
}; };
Python::ScopedInterpreterLock::ScopedInterpreterLock() Python::ScopedInterpreterLock::ScopedInterpreterLock()
@ -401,6 +396,31 @@ Python::ScopedInterpreterLock::ScopedInterpreterLock()
Python::ScopedInterpreterLock::~ScopedInterpreterLock() { delete impl_; } Python::ScopedInterpreterLock::~ScopedInterpreterLock() { delete impl_; }
class Python::ScopedInterpreterLockRelease::Impl {
public:
Impl() {
assert(HaveGIL());
// Release the GIL.
thread_state_ = PyEval_SaveThread();
}
~Impl() {
// Restore the GIL.
PyEval_RestoreThread(thread_state_);
}
private:
PyThreadState* thread_state_{};
};
Python::ScopedInterpreterLockRelease::ScopedInterpreterLockRelease()
: impl_{new Python::ScopedInterpreterLockRelease::Impl()}
// impl_{std::make_unique<Python::ScopedInterpreterLock::Impl>()}
{}
Python::ScopedInterpreterLockRelease::~ScopedInterpreterLockRelease() {
delete impl_;
}
// (some stuff borrowed from python's source code - used in our overriding of // (some stuff borrowed from python's source code - used in our overriding of
// objects' dir() results) // objects' dir() results)

View File

@ -39,9 +39,9 @@ class Python {
BA_DISALLOW_CLASS_COPIES(ScopedCallLabel); BA_DISALLOW_CLASS_COPIES(ScopedCallLabel);
}; };
/// Use this to protect Python code that may be run in cases where we don't /// Use this to protect Python code that may be run in cases where we
/// hold the Global Interpreter Lock (GIL) (basically anything outside of the /// don't hold the Global Interpreter Lock (GIL). (Basically anything
/// logic thread). /// outside of the logic thread).
class ScopedInterpreterLock { class ScopedInterpreterLock {
public: public:
ScopedInterpreterLock(); ScopedInterpreterLock();
@ -55,7 +55,20 @@ class Python {
Impl* impl_{}; Impl* impl_{};
}; };
// static auto Create() -> Python*; /// Use this for cases where we *do* hold the GIL but want to release
/// it for some operation.
class ScopedInterpreterLockRelease {
public:
ScopedInterpreterLockRelease();
~ScopedInterpreterLockRelease();
private:
class Impl;
// Note: should use unique_ptr for this, but build fails on raspberry pi
// (gcc 8.3.0). Works on Ubuntu 9.3 so should try again later.
// std::unique_ptr<Impl> impl_{};
Impl* impl_{};
};
/// Return whether the current thread holds the global-interpreter-lock. /// Return whether the current thread holds the global-interpreter-lock.
/// We must always hold the GIL while running python code. /// We must always hold the GIL while running python code.

6
src/external/readlinktest.c vendored Normal file
View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main(int argc, char** argv) {
printf("HELLO WORLD!\n");
return 0;
}

View File

@ -16,26 +16,38 @@ from efrotools import PYVER
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
# Suffix for the pyc files we include in stagings. # Suffix for the pyc files we include in stagings. We're using
# We're using deterministic opt pyc files; see PEP 552. # deterministic opt pyc files; see PEP 552.
# Note: this means anyone wanting to modify .py files in a build #
# will need to wipe out the existing .pyc files first or the changes # Note: this means anyone
# will be ignored. # wanting to modify .py files in a build will need to wipe out the
# existing .pyc files first or the changes will be ignored.
OPT_PYC_SUFFIX = 'cpython-' + PYVER.replace('.', '') + '.opt-1.pyc' OPT_PYC_SUFFIX = 'cpython-' + PYVER.replace('.', '') + '.opt-1.pyc'
class Config: def stage_assets(projroot: str, args: list[str] | None = None) -> None:
"""Encapsulates command options.""" """Stage assets for a build."""
if args is None:
args = sys.argv
AssetStager(projroot).run(args)
class AssetStager:
"""Context for a run of the tool."""
def __init__(self, projroot: str) -> None: def __init__(self, projroot: str) -> None:
self.projroot = projroot self.projroot = projroot
# We always calc src relative to this script. # We always calc src relative to this script.
self.src = self.projroot + '/build/assets' self.src = f'{self.projroot}/build/assets'
self.dst: str | None = None self.dst: str | None = None
self.serverdst: str | None = None self.serverdst: str | None = None
self.win_extras_src: str | None = None self.win_extras_src: str | None = None
self.win_platform: str | None = None self.win_platform: str | None = None
self.win_type: str | None = None self.win_type: str | None = None
self.include_python_dylib = False
self.include_shell_launcher = False
self.include_audio = True self.include_audio = True
self.include_meshes = True self.include_meshes = True
self.include_collision_meshes = True self.include_collision_meshes = True
@ -51,11 +63,105 @@ class Config:
self.is_payload_full = False self.is_payload_full = False
self.debug: bool | None = None self.debug: bool | None = None
def run(self, args: list[str]) -> None:
"""Do the thing."""
self._parse_args(args)
# Ok, now for every top level dir in src, come up with a nice single
# command to sync the needed subset of it to dst.
# We can now use simple speedy timestamp based updates since we no
# longer have to try to preserve timestamps to get .pyc files to
# behave (hooray!)
# Do our stripped down pylib dir for platforms that use that.
if self.include_pylib:
self._sync_pylib()
else:
if self.dst is not None and os.path.isdir(f'{self.dst}/pylib'):
subprocess.run(['rm', '-rf', f'{self.dst}/pylib'], check=True)
# Sync our server files if we're doing that.
if self.serverdst is not None:
self._sync_server_files()
# On windows we need to pull in some dlls and this and that (we also
# include a non-stripped-down set of Python libs).
if self.win_extras_src is not None:
self._sync_windows_extras()
# Standard stuff in ba_data.
self._sync_ba_data()
# On Android we need to build a payload file so it knows what to
# pull out of the apk.
if self.include_payload_file:
assert self.dst is not None
_write_payload_file(self.dst, self.is_payload_full)
def _parse_args(self, args: list[str]) -> None:
"""Parse args and apply to ourself."""
if len(args) < 1:
raise RuntimeError('Expected at least one argument.')
platform_arg = args[0]
# Require either -debug or -release in args.
if '-debug' in args:
self.debug = True
assert '-release' not in args
elif '-release' in args:
self.debug = False
else:
raise RuntimeError(
"Expected either '-debug' or '-release' in args."
)
if platform_arg == '-android':
self._parse_android_args(args)
elif platform_arg.startswith('-win'):
self._parse_win_args(platform_arg, args)
elif platform_arg == '-cmake':
self.dst = args[-1]
self.tex_suffix = '.dds'
elif platform_arg == '-cmakemodular':
self.dst = args[-1]
self.tex_suffix = '.dds'
self.include_python_dylib = True
self.include_shell_launcher = True
elif platform_arg == '-cmakeserver':
self.dst = os.path.join(args[-1], 'dist')
self.serverdst = args[-1]
self.include_textures = False
self.include_audio = False
self.include_meshes = False
elif platform_arg == '-xcode-mac':
self.src = os.environ['SOURCE_ROOT'] + '/build/assets'
self.dst = (
os.environ['TARGET_BUILD_DIR']
+ '/'
+ os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']
)
self.include_pylib = True
self.pylib_src_name = 'pylib-apple'
self.tex_suffix = '.dds'
elif platform_arg == '-xcode-ios':
self.src = os.environ['SOURCE_ROOT'] + '/build/assets'
self.dst = (
os.environ['TARGET_BUILD_DIR']
+ '/'
+ os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']
)
self.include_pylib = True
self.pylib_src_name = 'pylib-apple'
self.tex_suffix = '.pvr'
else:
raise RuntimeError('No valid platform arg provided.')
def _parse_android_args(self, args: list[str]) -> None: def _parse_android_args(self, args: list[str]) -> None:
# On Android we get nitpicky with what # On Android we get nitpicky with exactly what we want to copy
# we want to copy in since we can speed up # in since we can speed up iterations by installing stripped
# iterations by installing stripped down # down apks.
# apks.
self.dst = 'assets/ballistica_files' self.dst = 'assets/ballistica_files'
self.pylib_src_name = 'pylib-android' self.pylib_src_name = 'pylib-android'
self.include_payload_file = True self.include_payload_file = True
@ -98,9 +204,9 @@ class Config:
elif arg == '-audio': elif arg == '-audio':
self.include_audio = True self.include_audio = True
def _parse_win_platform(self, platform: str, args: list[str]) -> None: def _parse_win_args(self, platform: str, args: list[str]) -> None:
"""Parse sub-args in the windows platform string.""" """Parse sub-args in the windows platform string."""
winempty, wintype, winplt, wincfg = platform.split('-') winempty, wintype, winplt = platform.split('-')
self.win_platform = winplt self.win_platform = winplt
self.win_type = wintype self.win_type = wintype
assert winempty == '' assert winempty == ''
@ -115,78 +221,375 @@ class Config:
self.include_audio = False self.include_audio = False
self.include_meshes = False self.include_meshes = False
else: else:
raise RuntimeError(f'Invalid wintype: "{wintype}"') raise RuntimeError(f"Invalid wintype: '{wintype}'.")
if winplt == 'Win32': if winplt == 'Win32':
self.win_extras_src = self.projroot + '/build/assets/windows/Win32' self.win_extras_src = f'{self.projroot}/build/assets/windows/Win32'
elif winplt == 'x64': elif winplt == 'x64':
self.win_extras_src = self.projroot + '/build/assets/windows/x64' self.win_extras_src = f'{self.projroot}/build/assets/windows/x64'
else: else:
raise RuntimeError(f'Invalid winplt: "{winplt}"') raise RuntimeError(f"Invalid winplt: '{winplt}'.")
if wincfg == 'Debug': def _sync_windows_extras(self) -> None:
self.debug = True # pylint: disable=too-many-branches
elif wincfg == 'Release': assert self.win_extras_src is not None
self.debug = False assert self.win_platform is not None
assert self.win_type is not None
if not os.path.isdir(self.win_extras_src):
raise RuntimeError(
f"Win extras src dir not found: '{self.win_extras_src}'."
)
# Ok, lets do full syncs on each subdir we find so we properly
# delete anything in dst that disappeared from src. Lastly we'll
# sync over the remaining top level files. Note: technically it'll
# be possible to leave orphaned top level files in dst, so when
# building packages/etc. we should always start from scratch.
assert self.dst is not None
assert self.debug is not None
pyd_rules: list[str]
if self.debug:
pyd_rules = ['--include', '*_d.pyd']
else: else:
raise RuntimeError(f'Invalid wincfg: "{wincfg}"') pyd_rules = ['--exclude', '*_d.pyd', '--include', '*.pyd']
def parse_args(self, args: list[str]) -> None: for dirname in ('DLLs', 'Lib'):
"""Parse args and apply to the cfg.""" # EWW: seems Windows Python currently sets its path to ./lib but
if len(args) < 1: # it comes with Lib. Windows is normally case-insensitive but
raise RuntimeError('Expected a platform argument.') # this messes it up when running under WSL. Let's install it as
platform = args[0] # lib for now.
if platform == '-android': dstdirname = 'lib' if dirname == 'Lib' else dirname
self._parse_android_args(args) os.makedirs(f'{self.dst}/{dstdirname}', exist_ok=True)
elif platform.startswith('-win'): cmd: list[str] = (
self._parse_win_platform(platform, args) [
elif platform == '-cmake': 'rsync',
self.dst = args[1] '--recursive',
self.tex_suffix = '.dds' '--times',
elif '-cmakeserver' in args: '--delete',
self.dst = os.path.join(args[-1], 'dist') '--delete-excluded',
self.serverdst = args[-1] '--prune-empty-dirs',
self.include_textures = False '--include',
self.include_audio = False '*.ico',
self.include_meshes = False '--include',
'*.cat',
'--include',
'*.dll',
]
+ pyd_rules
+ [
'--include',
'*.py',
'--include',
f'*.{OPT_PYC_SUFFIX}',
'--include',
'*/',
'--exclude',
'*',
f'{os.path.join(self.win_extras_src, dirname)}/',
f'{self.dst}/{dstdirname}/',
]
)
subprocess.run(cmd, check=True)
# Require either -debug or -release in args. # Now sync the top level individual files that we want. We could
# FIXME: should require this for all platforms for consistency. # technically copy everything over but this keeps staging dirs a bit
if '-debug' in args: # tidier.
self.debug = True dbgsfx = '_d' if self.debug else ''
assert '-release' not in args
elif '-release' in args: # Note: Needs updating when Python version changes (currently 3.11).
self.debug = False toplevelfiles: list[str] = [f'python311{dbgsfx}.dll']
if self.win_type == 'win':
toplevelfiles += [
'libvorbis.dll',
'libvorbisfile.dll',
'ogg.dll',
'OpenAL32.dll',
'SDL2.dll',
]
elif self.win_type == 'winserver':
toplevelfiles += [f'python{dbgsfx}.exe']
# Include debug dlls so folks without msvc can run them.
if self.debug:
if self.win_platform == 'x64':
toplevelfiles += [
'msvcp140d.dll',
'vcruntime140d.dll',
'vcruntime140_1d.dll',
'ucrtbased.dll',
]
else: else:
raise RuntimeError( toplevelfiles += [
"Expected either '-debug' or '-release' in args." 'msvcp140d.dll',
) 'vcruntime140d.dll',
elif '-xcode-mac' in args: 'ucrtbased.dll',
self.src = os.environ['SOURCE_ROOT'] + '/build/assets' ]
self.dst = (
os.environ['TARGET_BUILD_DIR'] # Include the runtime redistributables in release builds.
+ '/' if not self.debug:
+ os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH'] if self.win_platform == 'x64':
) toplevelfiles.append('vc_redist.x64.exe')
self.include_pylib = True elif self.win_platform == 'Win32':
self.pylib_src_name = 'pylib-apple' toplevelfiles.append('vc_redist.x86.exe')
self.tex_suffix = '.dds' else:
elif '-xcode-ios' in args: raise RuntimeError(f'Invalid win_platform {self.win_platform}')
self.src = os.environ['SOURCE_ROOT'] + '/build/assets'
self.dst = ( cmd2 = (
os.environ['TARGET_BUILD_DIR'] ['rsync', '--times']
+ '/' + [os.path.join(self.win_extras_src, f) for f in toplevelfiles]
+ os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH'] + [f'{self.dst}/']
) )
self.include_pylib = True subprocess.run(cmd2, check=True)
self.pylib_src_name = 'pylib-apple'
self.tex_suffix = '.pvr' # If we're running under WSL we won't be able to launch these .exe
# files unless they're marked executable, so do that here. Update:
# gonna try simply setting this flag on the source side.
# _run(f'chmod +x {self.dst}/*.exe')
def _sync_pylib(self) -> None:
assert self.pylib_src_name is not None
assert self.dst is not None
os.makedirs(f'{self.dst}/pylib', exist_ok=True)
cmd: list[str] = [
'rsync',
'--recursive',
'--times',
'--delete',
'--delete-excluded',
'--prune-empty-dirs',
'--include',
'*.py',
'--include',
f'*.{OPT_PYC_SUFFIX}',
'--include',
'*/',
'--exclude',
'*',
f'{self.src}/{self.pylib_src_name}/',
f'{self.dst}/pylib/',
]
subprocess.run(cmd, check=True)
def _sync_ba_data(self) -> None:
assert self.dst is not None
os.makedirs(f'{self.dst}/ba_data', exist_ok=True)
cmd: list[str] = [
'rsync',
'--recursive',
'--times',
'--delete',
'--prune-empty-dirs',
]
# Normally we use --delete-excluded so that we can do sparse
# syncs for quick iteration on android apks/etc. However for our
# modular builds we need to avoid that flag because we do a
# second pass after to sync in our python-dylib stuff and with
# that flag it all gets blown on the first pass.
if not self.include_python_dylib:
cmd.append('--delete-excluded')
else: else:
raise RuntimeError('No valid platform arg provided.') # Shouldn't be trying to do sparse stuff.
assert (
self.include_textures
and self.include_audio
and self.include_fonts
and self.include_json
and self.include_meshes
and self.include_collision_meshes
)
# Keep rsync from trying to prune this as an 'empty' dir.
cmd += ['--exclude', '/python-dylib']
if self.include_scripts:
cmd += [
'--include',
'*.py',
'--include',
'*.pem',
'--include',
f'*.{OPT_PYC_SUFFIX}',
]
if self.include_textures:
assert self.tex_suffix is not None
cmd += ['--include', f'*{self.tex_suffix}']
if self.include_audio:
cmd += ['--include', '*.ogg']
if self.include_fonts:
cmd += ['--include', '*.fdata']
if self.include_json:
cmd += ['--include', '*.json']
if self.include_meshes:
cmd += ['--include', '*.bob']
if self.include_collision_meshes:
cmd += ['--include', '*.cob']
# By default we want to include all dirs and exclude all files.
cmd += [
'--include',
'*/',
'--exclude',
'*',
f'{self.src}/ba_data/',
f'{self.dst}/ba_data/',
]
subprocess.run(cmd, check=True)
if self.include_python_dylib:
self._sync_python_dylib()
if self.include_shell_launcher:
self._sync_shell_launcher()
def _sync_shell_launcher(self) -> None:
path = f'{self.dst}/ballisticakit'
# For now this is so simple we just do an ad-hoc write each time;
# not worth setting up files and syncs.
if self.debug:
optstuff = 'export PYTHONDEVMODE=1\nexport PYTHONOPTIMIZE=0\n'
else:
optstuff = 'export PYTHONDEVMODE=0\nexport PYTHONOPTIMIZE=1\n'
optnm = 'DEBUG' if self.debug else 'RELEASE'
with open(path, 'w', encoding='utf-8') as outfile:
outfile.write(
'#!/bin/sh\n'
'\n'
'# We should error if anything here errors.\n'
'set -e\n'
'\n'
'# We want Python to use UTF-8 everywhere for consistency.\n'
'# (This will be the default in the future; see PEP 686).\n'
f'export PYTHONUTF8=1\n'
'\n'
f'# This is a Ballistica {optnm} build; set Python to match.\n'
f'{optstuff}'
'\n'
'# Run the app, forwarding along all arguments.\n'
'# Basically this does:\n'
'# import baenv; baenv.configure();'
' import babase; babase.app.run().\n'
'python3.11 ba_data/python/baenv.py $@\n'
)
subprocess.run(['chmod', '+x', path], check=True)
def _sync_python_dylib(self) -> None:
# pylint: disable=too-many-locals
from batools.featureset import FeatureSet
# Note: we're technically not *syncing* quite so much as
# *constructing* here.
dylib_staging_dir = f'{self.dst}/ba_data/python-dylib'
# Name of our single shared library containing all our stuff.
soname = 'ballisticakit.so'
# All featuresets in the project with binary modules.
bmodfeaturesets = {
f.name: f
for f in FeatureSet.get_all_for_project(self.projroot)
if f.has_python_binary_module
}
# Map of featureset names (foo) to module filenames (_foo.so).
fsetmfilenames = {
f.name: f'{f.name_python_binary_module}.so'
for f in bmodfeaturesets.values()
}
# Set of all module filenames (_foo.so, etc.) we should have.
fsetmfilenamevals = set(fsetmfilenames.values())
if not os.path.exists(dylib_staging_dir):
os.makedirs(dylib_staging_dir, exist_ok=True)
# Create a symlink to our original built so. NOTE: Anyone
# building final app packages/etc. should replace this with the
# actual file. This is just for development.
# FIXME - currently assuming our built .so lives one dir above
# our staging dir; should not be making that assumption.
built_so_path = f'{self.dst}/../{soname}'
staged_so_path = f'{dylib_staging_dir}/{soname}'
if not os.path.islink(staged_so_path):
relpath = os.path.relpath(built_so_path, dylib_staging_dir)
subprocess.run(['ln', '-sf', relpath, staged_so_path], check=True)
# Ok, now we want to create symlinks for each of our featureset
# Python modules. All of our stuff lives in the same .so and we
# can use symlinks to help Python find them all there. See the
# following:
# https://peps.python.org/pep-0489/#multiple-modules-in-one-library
for fsetname, featureset in bmodfeaturesets.items():
if featureset.has_python_binary_module:
mfilename = fsetmfilenames[fsetname]
instpath = f'{dylib_staging_dir}/{mfilename}'
if not os.path.islink(instpath):
subprocess.run(['ln', '-sf', soname, instpath], check=True)
# Lastly, blow away anything in that dir that's not something we
# just made (clears out featuresets that get renamed or
# disabled, etc).
fnames = os.listdir(dylib_staging_dir)
for fname in fnames:
if not fname in fsetmfilenamevals and fname != soname:
fpath = f'{dylib_staging_dir}/{fname}'
print(f"Pruning orphaned dylib path: '{fpath}'.")
subprocess.run(['rm', '-rf', fpath], check=True)
def _sync_server_files(self) -> None:
assert self.serverdst is not None
assert self.debug is not None
modeval = 'debug' if self.debug else 'release'
# NOTE: staging these directly from src; not build.
_stage_server_file(
projroot=self.projroot,
mode=modeval,
infilename=f'{self.projroot}/src/assets/server_package/'
'ballisticakit_server.py',
outfilename=os.path.join(
self.serverdst,
'ballisticakit_server.py'
if self.win_type is not None
else 'ballisticakit_server',
),
)
_stage_server_file(
projroot=self.projroot,
mode=modeval,
infilename=f'{self.projroot}/src/assets/server_package/README.txt',
outfilename=os.path.join(self.serverdst, 'README.txt'),
)
_stage_server_file(
projroot=self.projroot,
mode=modeval,
infilename=f'{self.projroot}/src/assets/server_package/'
'config_template.yaml',
outfilename=os.path.join(self.serverdst, 'config_template.yaml'),
)
if self.win_type is not None:
fname = 'launch_ballisticakit_server.bat'
_stage_server_file(
projroot=self.projroot,
mode=modeval,
infilename=f'{self.projroot}/src/assets/server_package/{fname}',
outfilename=os.path.join(self.serverdst, fname),
)
def md5sum(filename: str) -> str: def _filehash(filename: str) -> str:
"""Generate an md5sum given a filename.""" """Generate a hash for a file."""
md5 = hashlib.md5() md5 = hashlib.md5()
with open(filename, mode='rb') as infile: with open(filename, mode='rb') as infile:
for buf in iter(partial(infile.read, 1024), b''): for buf in iter(partial(infile.read, 1024), b''):
@ -194,18 +597,9 @@ def md5sum(filename: str) -> str:
return md5.hexdigest() return md5.hexdigest()
def _run(cmd: str, echo: bool = False) -> None:
"""Run an os command; raise Exception on non-zero return value."""
if echo:
print(cmd)
result = os.system(cmd)
if result != 0:
raise RuntimeError(f"Error running cmd: '{cmd}'.")
def _write_payload_file(assets_root: str, full: bool) -> None: def _write_payload_file(assets_root: str, full: bool) -> None:
if not assets_root.endswith('/'): if not assets_root.endswith('/'):
assets_root = assets_root + '/' assets_root = f'{assets_root}/'
# Now construct a payload file if we have any files. # Now construct a payload file if we have any files.
file_list = [] file_list = []
@ -222,226 +616,24 @@ def _write_payload_file(assets_root: str, full: bool) -> None:
raise RuntimeError( raise RuntimeError(
f"Invalid filename (contains spaces): '{fpathshort}'" f"Invalid filename (contains spaces): '{fpathshort}'"
) )
payload_str += fpathshort + ' ' + md5sum(fpath) + '\n' payload_str += f'{fpathshort} {_filehash(fpath)}\n'
file_list.append(fpathshort) file_list.append(fpathshort)
payload_path = assets_root + '/payload_info' payload_path = f'{assets_root}/payload_info'
if file_list: if file_list:
# Write the file count, whether this is a 'full' payload, and finally # Write the file count, whether this is a 'full' payload, and
# the file list. # finally the file list.
payload_str = ( fullstr = '1' if full else '0'
str(len(file_list)) payload_str = f'{len(file_list)}\n{fullstr}\n{payload_str}'
+ '\n'
+ ('1' if full else '0')
+ '\n'
+ payload_str
)
with open(payload_path, 'w', encoding='utf-8') as outfile: with open(payload_path, 'w', encoding='utf-8') as outfile:
outfile.write(payload_str) outfile.write(payload_str)
else: else:
# Remove the payload file; this will cause the game to completely # Remove the payload file; this will cause the game to
# skip the payload processing step. # completely skip the payload processing step.
if os.path.exists(payload_path): if os.path.exists(payload_path):
os.unlink(payload_path) os.unlink(payload_path)
def _sync_windows_extras(cfg: Config) -> None:
# pylint: disable=too-many-branches
assert cfg.win_extras_src is not None
assert cfg.win_platform is not None
assert cfg.win_type is not None
if not os.path.isdir(cfg.win_extras_src):
raise RuntimeError(
"Win extras src dir not found: '{cfg.win_extras_src}'."
)
# Ok, lets do full syncs on each subdir we find so we
# properly delete anything in dst that disappeared from src.
# Lastly we'll sync over the remaining top level files.
# Note: technically it'll be possible to leave orphaned top level
# files in dst, so when building packages/etc. we should always start
# from scratch.
assert cfg.dst is not None
assert cfg.debug is not None
if cfg.debug:
pyd_rules = "--include '*_d.pyd'"
else:
pyd_rules = "--exclude '*_d.pyd' --include '*.pyd'"
for dirname in ('DLLs', 'Lib'):
# EWW: seems windows python currently sets its path to ./lib but it
# comes with Lib. Windows is normally case-insensitive but this messes
# it up when running under WSL. Let's install it as lib for now.
dstdirname = 'lib' if dirname == 'Lib' else dirname
_run(f'mkdir -p "{cfg.dst}/{dstdirname}"')
cmd = (
'rsync --recursive --update --delete --delete-excluded '
' --prune-empty-dirs'
" --include '*.ico' --include '*.cat'"
f" --include '*.dll' {pyd_rules}"
" --include '*.py' --include '*." + OPT_PYC_SUFFIX + "'"
" --include '*/' --exclude '*' \""
+ os.path.join(cfg.win_extras_src, dirname)
+ '/" '
'"' + cfg.dst + '/' + dstdirname + '/"'
)
_run(cmd)
# Now sync the top level individual files that we want.
# We could technically copy everything over but this keeps staging
# dirs a bit tidier.
dbgsfx = '_d' if cfg.debug else ''
# Note: Below needs updating when Python version changes (currently 3.11)
toplevelfiles: list[str] = [f'python311{dbgsfx}.dll']
if cfg.win_type == 'win':
toplevelfiles += [
'libvorbis.dll',
'libvorbisfile.dll',
'ogg.dll',
'OpenAL32.dll',
'SDL2.dll',
]
elif cfg.win_type == 'winserver':
toplevelfiles += [f'python{dbgsfx}.exe']
# Include debug dlls so folks without msvc can run them.
if cfg.debug:
if cfg.win_platform == 'x64':
toplevelfiles += [
'msvcp140d.dll',
'vcruntime140d.dll',
'vcruntime140_1d.dll',
'ucrtbased.dll',
]
else:
toplevelfiles += [
'msvcp140d.dll',
'vcruntime140d.dll',
'ucrtbased.dll',
]
# Include the runtime redistributables in release builds.
if not cfg.debug:
if cfg.win_platform == 'x64':
toplevelfiles.append('vc_redist.x64.exe')
elif cfg.win_platform == 'Win32':
toplevelfiles.append('vc_redist.x86.exe')
else:
raise RuntimeError(f'Invalid win_platform {cfg.win_platform}')
cmd2 = (
['rsync', '--update']
+ [os.path.join(cfg.win_extras_src, f) for f in toplevelfiles]
+ [cfg.dst + '/']
)
subprocess.run(cmd2, check=True)
# If we're running under WSL we won't be able to launch these .exe files
# unless they're marked executable, so do that here.
# Update: gonna try simply setting this flag on the source side.
# _run(f'chmod +x {cfg.dst}/*.exe')
def _sync_pylib(cfg: Config) -> None:
assert cfg.pylib_src_name is not None
assert cfg.dst is not None
_run(f'mkdir -p "{cfg.dst}/pylib"')
cmd = (
f'rsync --recursive --update --delete --delete-excluded '
f' --prune-empty-dirs'
f" --include '*.py' --include '*.{OPT_PYC_SUFFIX}'"
f" --include '*/' --exclude '*'"
f' "{cfg.src}/{cfg.pylib_src_name}/" '
f'"{cfg.dst}/pylib/"'
)
_run(cmd)
def _sync_standard_game_data(cfg: Config) -> None:
assert cfg.dst is not None
_run('mkdir -p "' + cfg.dst + '/ba_data"')
cmd = (
'rsync --recursive --update --delete --delete-excluded'
' --prune-empty-dirs'
)
if cfg.include_scripts:
cmd += (
f" --include '*.py' --include '*.pem'"
f" --include '*.{OPT_PYC_SUFFIX}'"
)
if cfg.include_textures:
assert cfg.tex_suffix is not None
cmd += " --include '*" + cfg.tex_suffix + "'"
if cfg.include_audio:
cmd += " --include '*.ogg'"
if cfg.include_fonts:
cmd += " --include '*.fdata'"
if cfg.include_json:
cmd += " --include '*.json'"
if cfg.include_meshes:
cmd += " --include '*.bob'"
if cfg.include_collision_meshes:
cmd += " --include '*.cob'"
cmd += (
" --include='*/' --exclude='*' \""
+ cfg.src
+ '/ba_data/" "'
+ cfg.dst
+ '/ba_data/"'
)
_run(cmd)
def _sync_server_files(cfg: Config) -> None:
assert cfg.serverdst is not None
assert cfg.debug is not None
modeval = 'debug' if cfg.debug else 'release'
# NOTE: staging these directly from src; not build.
stage_server_file(
projroot=cfg.projroot,
mode=modeval,
infilename=f'{cfg.projroot}/src/assets/server_package/'
'ballisticakit_server.py',
outfilename=os.path.join(
cfg.serverdst,
'ballisticakit_server.py'
if cfg.win_type is not None
else 'ballisticakit_server',
),
)
stage_server_file(
projroot=cfg.projroot,
mode=modeval,
infilename=f'{cfg.projroot}/src/assets/server_package/README.txt',
outfilename=os.path.join(cfg.serverdst, 'README.txt'),
)
stage_server_file(
projroot=cfg.projroot,
mode=modeval,
infilename=f'{cfg.projroot}/src/assets/server_package/'
'config_template.yaml',
outfilename=os.path.join(cfg.serverdst, 'config_template.yaml'),
)
if cfg.win_type is not None:
fname = 'launch_ballisticakit_server.bat'
stage_server_file(
projroot=cfg.projroot,
mode=modeval,
infilename=f'{cfg.projroot}/src/assets/server_package/{fname}',
outfilename=os.path.join(cfg.serverdst, fname),
)
def _write_if_changed( def _write_if_changed(
path: str, contents: str, make_executable: bool = False path: str, contents: str, make_executable: bool = False
) -> None: ) -> None:
@ -459,7 +651,7 @@ def _write_if_changed(
subprocess.run(['chmod', '+x', path], check=True) subprocess.run(['chmod', '+x', path], check=True)
def stage_server_file( def _stage_server_file(
projroot: str, mode: str, infilename: str, outfilename: str projroot: str, mode: str, infilename: str, outfilename: str
) -> None: ) -> None:
"""Stage files for the server environment with some filtering.""" """Stage files for the server environment with some filtering."""
@ -528,45 +720,3 @@ def stage_server_file(
_write_if_changed(outfilename, '\n'.join(lines) + '\n') _write_if_changed(outfilename, '\n'.join(lines) + '\n')
else: else:
raise RuntimeError(f"Unknown server file for staging: '{basename}'.") raise RuntimeError(f"Unknown server file for staging: '{basename}'.")
def main(projroot: str, args: list[str] | None = None) -> None:
"""Stage assets for a build."""
if args is None:
args = sys.argv
cfg = Config(projroot)
cfg.parse_args(args)
# Ok, now for every top level dir in src, come up with a nice single
# command to sync the needed subset of it to dst.
# We can now use simple speedy timestamp based updates since
# we no longer have to try to preserve timestamps to get .pyc files
# to behave (hooray!)
# Do our stripped down pylib dir for platforms that use that.
if cfg.include_pylib:
_sync_pylib(cfg)
else:
if cfg.dst is not None and os.path.isdir(cfg.dst + '/pylib'):
subprocess.run(['rm', '-rf', cfg.dst + '/pylib'], check=True)
# Sync our server files if we're doing that.
if cfg.serverdst is not None:
_sync_server_files(cfg)
# On windows we need to pull in some dlls and this and that
# (we also include a non-stripped-down set of python libs).
if cfg.win_extras_src is not None:
_sync_windows_extras(cfg)
# Standard stuff in ba_data
_sync_standard_game_data(cfg)
# On Android we need to build a payload file so it knows
# what to pull out of the apk.
if cfg.include_payload_file:
assert cfg.dst is not None
_write_payload_file(cfg.dst, cfg.is_payload_full)

View File

@ -937,7 +937,7 @@ def generate_dummy_modules(projroot: str) -> None:
# Generate a dummy module for each featureset that has a binary module. # Generate a dummy module for each featureset that has a binary module.
featuresets = FeatureSet.get_all_for_project(project_root=projroot) featuresets = FeatureSet.get_all_for_project(project_root=projroot)
featuresets = [f for f in featuresets if f.has_native_python_module] featuresets = [f for f in featuresets if f.has_python_binary_module]
mnames: list[str] = [fs.name_python_binary_module for fs in featuresets] mnames: list[str] = [fs.name_python_binary_module for fs in featuresets]
builddir = 'build/dummymodules' builddir = 'build/dummymodules'

View File

@ -54,7 +54,7 @@ class FeatureSet:
# its C++ code. The build process will try to create dummy # its C++ code. The build process will try to create dummy
# modules for all native modules, so to avoid errors you must # modules for all native modules, so to avoid errors you must
# tell it if you don't have one. # tell it if you don't have one.
self.has_native_python_module = True self.has_python_binary_module = True
# If True, for feature-set 'foo_bar', the build system will # If True, for feature-set 'foo_bar', the build system will
# define a 'babase.app.foo_bar' attr which points to a lazy # define a 'babase.app.foo_bar' attr which points to a lazy

View File

@ -806,11 +806,13 @@ def efro_gradle() -> None:
def stage_assets() -> None: def stage_assets() -> None:
"""Stage assets for a build.""" """Stage assets for a build."""
from batools.assetstaging import main import batools.assetstaging
from efro.error import CleanError from efro.error import CleanError
try: try:
main(projroot=str(PROJROOT), args=sys.argv[2:]) batools.assetstaging.stage_assets(
projroot=str(PROJROOT), args=sys.argv[2:]
)
except CleanError as exc: except CleanError as exc:
exc.pretty_print() exc.pretty_print()
sys.exit(1) sys.exit(1)

View File

@ -25,16 +25,48 @@ def gen_monolithic_register_modules() -> None:
featuresets = FeatureSet.get_all_for_project(str(PROJROOT)) featuresets = FeatureSet.get_all_for_project(str(PROJROOT))
# Filter out ones without native modules. # Filter out ones without native modules.
featuresets = [f for f in featuresets if f.has_native_python_module] featuresets = [f for f in featuresets if f.has_python_binary_module]
pymodulenames = sorted(f.name_python_binary_module for f in featuresets) pymodulenames = sorted(f.name_python_binary_module for f in featuresets)
def initname(mname: str) -> str:
# plus is a special case since we need to define that symbol
# ourself.
return f'DoPyInit_{mname}' if mname == '_baplus' else f'PyInit_{mname}'
extern_def_code = '\n'.join( extern_def_code = '\n'.join(
f'auto PyInit_{n}() -> PyObject*;' for n in pymodulenames f'auto {initname(n)}() -> PyObject*;' for n in pymodulenames
) )
py_register_code = '\n'.join( py_register_code = '\n'.join(
f'PyImport_AppendInittab("{n}", &PyInit_{n});' for n in pymodulenames f'PyImport_AppendInittab("{n}", &{initname(n)});' for n in pymodulenames
) )
if '_baplus' in pymodulenames:
init_plus_code = (
'\n'
'// Slight hack: because we are currently building baplus as a'
' static module\n'
'// and linking it in, symbols exported there (namely'
' PyInit__baplus) do not\n'
'// seem to be available through us when we are compiled as'
' a dynamic\n'
'// library. This leads to Python being unable to load baplus.'
' While I\'m sure\n'
'// there is some way to get those symbols exported, I\'m worried'
' it might be\n'
'// a messy platform-specific affair. So instead we\'re just'
' defining that\n'
'// function here when baplus is present and forwarding it through'
' to the\n'
'// static library version.\n'
'extern "C" auto PyInit__baplus() -> PyObject* {\n'
' return DoPyInit__baplus();\n'
'}\n'
)
else:
init_plus_code = ''
base_code = """ base_code = """
// Released under the MIT License. See LICENSE for details. // Released under the MIT License. See LICENSE for details.
@ -43,13 +75,12 @@ def gen_monolithic_register_modules() -> None:
// THIS CODE IS AUTOGENERATED BY META BUILD; DO NOT EDIT BY HAND. // THIS CODE IS AUTOGENERATED BY META BUILD; DO NOT EDIT BY HAND.
#include "ballistica/shared/ballistica.h"
#include "ballistica/shared/python/python_sys.h" #include "ballistica/shared/python/python_sys.h"
#if BA_MONOLITHIC_BUILD
extern "C" { extern "C" {
${EXTERN_DEF_CODE} ${EXTERN_DEF_CODE}
} }
#endif // BA_MONOLITHIC_BUILD
namespace ballistica { namespace ballistica {
@ -58,15 +89,15 @@ def gen_monolithic_register_modules() -> None:
/// binary modules get located as .so files on disk as per regular /// binary modules get located as .so files on disk as per regular
/// Python behavior. /// Python behavior.
void MonolithicRegisterPythonModules() { void MonolithicRegisterPythonModules() {
#if BA_MONOLITHIC_BUILD if (g_buildconfig.monolithic_build()) {
${PY_REGISTER_CODE} ${PY_REGISTER_CODE}
#else } else {
FatalError( FatalError(
"MonolithicRegisterPythonModules should not be called" "MonolithicRegisterPythonModules should not be called"
" in modular builds."); " in modular builds.");
#endif // BA_MONOLITHIC_BUILD }
} }
${PY_INIT_PLUS}
} // namespace ballistica } // namespace ballistica
#endif // BALLISTICA_CORE_MGEN_PYTHON_MODULES_MONOLITHIC_H_ #endif // BALLISTICA_CORE_MGEN_PYTHON_MODULES_MONOLITHIC_H_
@ -74,7 +105,10 @@ def gen_monolithic_register_modules() -> None:
out = ( out = (
textwrap.dedent(base_code) textwrap.dedent(base_code)
.replace('${EXTERN_DEF_CODE}', extern_def_code) .replace('${EXTERN_DEF_CODE}', extern_def_code)
.replace('${PY_REGISTER_CODE}', textwrap.indent(py_register_code, ' ')) .replace(
'${PY_REGISTER_CODE}', textwrap.indent(py_register_code, ' ')
)
.replace('${PY_INIT_PLUS}', init_plus_code)
.strip() .strip()
+ '\n' + '\n'
) )
@ -84,19 +118,6 @@ def gen_monolithic_register_modules() -> None:
outfile.write(out) outfile.write(out)
def stage_server_file() -> None:
"""Stage files for the server environment with some filtering."""
from efro.error import CleanError
import batools.assetstaging
if len(sys.argv) != 5:
raise CleanError('Expected 3 args (mode, infile, outfile).')
mode, infilename, outfilename = sys.argv[2], sys.argv[3], sys.argv[4]
batools.assetstaging.stage_server_file(
str(PROJROOT), mode, infilename, outfilename
)
def py_examine() -> None: def py_examine() -> None:
"""Run a python examination at a given point in a given file.""" """Run a python examination at a given point in a given file."""
import os import os
@ -244,7 +265,7 @@ def update_cmake_prefab_lib() -> None:
) )
suffix = '_server' if buildtype == 'server' else '_gui' suffix = '_server' if buildtype == 'server' else '_gui'
target = ( target = (
f'build/prefab/lib/{platform}{suffix}/{mode}/' f'libballistica_plus.a' f'build/prefab/lib/{platform}{suffix}/{mode}/' f'libballisticaplus.a'
) )
# Build the target and then copy it to dst if it doesn't exist there yet # Build the target and then copy it to dst if it doesn't exist there yet
@ -252,7 +273,7 @@ def update_cmake_prefab_lib() -> None:
subprocess.run(['make', target], check=True) subprocess.run(['make', target], check=True)
libdir = os.path.join(builddir, 'prefablib') libdir = os.path.join(builddir, 'prefablib')
libpath = os.path.join(libdir, 'libballistica_plus.a') libpath = os.path.join(libdir, 'libballisticaplus.a')
update = True update = True
time1 = os.path.getmtime(target) time1 = os.path.getmtime(target)

View File

@ -788,7 +788,7 @@ class SpinoffContext:
# Strip precompiled plus library out of the cmake file. # Strip precompiled plus library out of the cmake file.
text = replace_exact( text = replace_exact(
text, text,
'${CMAKE_CURRENT_BINARY_DIR}/prefablib/libballistica_plus.a' '${CMAKE_CURRENT_BINARY_DIR}/prefablib/libballisticaplus.a'
' ode ', ' ode ',
'ode ', 'ode ',
label=src_path, label=src_path,

View File

@ -714,42 +714,77 @@ def _patch_py_wreadlink_test() -> None:
fname = 'Python/fileutils.c' fname = 'Python/fileutils.c'
txt = readfile(fname) txt = readfile(fname)
# Final fix for this problem.
# It seems that readlink() might be broken in android at the moment,
# returning an int while claiming it to be a ssize_t value. This makes
# the error case (-1) actually come out as 4294967295. When cast back
# to an int it is -1, so that's what we do. This should be fine to do
# even on a fixed version.
txt = replace_exact( txt = replace_exact(
txt, txt,
' res = readlink(cpath, cbuf, cbuf_len);\n', ' res = readlink(cpath, cbuf, cbuf_len);\n',
( ' res = (int)readlink(cpath, cbuf, cbuf_len);\n',
' res = readlink(cpath, cbuf, cbuf_len);\n'
' const wchar_t *path2 = path;\n'
' int path2len = 0;\n'
' while (*path2) {\n'
' path2++;\n'
' path2len++;\n'
' }\n'
' char dlog1[512];\n'
' if (res >= 0) {\n'
' snprintf(dlog1, sizeof(dlog1), "ValsA1 pathlen=%d slen=%d'
' path=\'%s\'", path2len, strlen(cpath), cpath);\n'
' } else {\n'
' snprintf(dlog1, sizeof(dlog1), "ValsA2 pathlen=%d",'
' path2len);\n'
' }\n'
' Py_BallisticaLowLevelDebugLog(dlog1);\n'
),
) )
txt = replace_exact( # Verbose problem exploration:
txt, # txt = replace_exact(
" cbuf[res] = '\\0'; /* buf will be null terminated */", # txt,
( # '#include <stdlib.h> // mbstowcs()\n',
' char dlog[512];\n' # '#include <stdlib.h> // mbstowcs()\n'
' snprintf(dlog, sizeof(dlog), "ValsB res=%d resx=%X' # '#include <sys/syscall.h>\n',
' eq1=%d eq2=%d",' # )
' (int)res, res, (int)(res == -1),'
' (int)((size_t)res == cbuf_len));\n' # txt = replace_exact(txt, ' Py_ssize_t res;\n', '')
' Py_BallisticaLowLevelDebugLog(dlog);\n'
" cbuf[res] = '\\0'; /* buf will be null terminated */" # txt = replace_exact(
), # txt,
) # ' res = readlink(cpath, cbuf, cbuf_len);\n',
# (
# ' Py_ssize_t res = readlink(cpath, cbuf, cbuf_len);\n'
# ' Py_ssize_t res2 = readlink(cpath, cbuf, cbuf_len);\n'
# ' ssize_t res3 = readlink(cpath, cbuf, cbuf_len);\n'
# ' ssize_t res4 = readlinkat(AT_FDCWD, cpath,
# cbuf, cbuf_len);\n'
# ' int res5 = syscall(SYS_readlinkat, AT_FDCWD, cpath,'
# ' cbuf, cbuf_len);\n'
# ' ssize_t res6 = syscall(SYS_readlinkat, AT_FDCWD, cpath,'
# ' cbuf, cbuf_len);\n'
# ' char dlog[512];\n'
# ' snprintf(dlog, sizeof(dlog),'
# ' "res=%zd res2=%zd res3=%zd res4=%zd res5=%d res6=%zd"\n'
# ' " (res == -1)=%d (res2 == -1)=%d (res3 == -1)=%d'
# ' (res4 == -1)=%d (res5 == -1)=%d (res6 == -1)=%d",\n'
# ' res, res2, res3, res4, res5, res6,\n'
# ' (res == -1), (res2 == -1), (res3 == -1),'
# ' (res4 == -1), (res5 == -1), (res6 == -1));\n'
# ' Py_BallisticaLowLevelDebugLog(dlog);\n'
# '\n'
# ' char dlog1[512];\n'
# ' ssize_t st1;\n'
# ' Py_ssize_t st2;\n'
# ' snprintf(dlog1, sizeof(dlog1),
# "ValsA1 sz1=%zu sz2=%zu res=%zd'
# ' res_hex=%lX res_cmp=%d res_cmp_2=%d pathlen=%d slen=%d'
# ' path=\'%s\'", sizeof(st1), sizeof(st2), res,'
# ' res, (int)(res == -1), (int)((int)res == -1),'
# ' (int)wcslen(path), (int)strlen(cpath), cpath);\n'
# ' Py_BallisticaLowLevelDebugLog(dlog1);\n'
# ),
# )
# txt = replace_exact(
# txt,
# " cbuf[res] = '\\0'; /* buf will be null terminated */",
# (
# ' char dlog[512];\n'
# ' snprintf(dlog, sizeof(dlog), "ValsB res=%d resx=%lX'
# ' eq1=%d eq2=%d",'
# ' (int)res, res, (int)(res == -1),'
# ' (int)((size_t)res == cbuf_len));\n'
# ' Py_BallisticaLowLevelDebugLog(dlog);\n'
# " cbuf[res] = '\\0'; /* buf will be null terminated */"
# ),
# )
writefile(fname, txt) writefile(fname, txt)

View File

@ -114,7 +114,6 @@ from batools.pcommand import (
from batools.pcommand2 import ( from batools.pcommand2 import (
gen_python_init_module, gen_python_init_module,
gen_monolithic_register_modules, gen_monolithic_register_modules,
stage_server_file,
py_examine, py_examine,
clean_orphaned_assets, clean_orphaned_assets,
win_ci_install_prereqs, win_ci_install_prereqs,