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/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/48/ab/8cddfcde36a750856f3f81dd20c8",
"build/assets/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/2b/46/8aedfa8741090247f04eb9e6df55",
"build/assets/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/a1/f9/645b8c7e1e99dd11446bc77005da",
"build/assets/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/83/87/06fc7255ebf8a895ad37d2dfa13d",
"build/assets/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/b8/5e/c8766634397fb77ae3a407c05d63",
"build/assets/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/6f/38/958616d8cb85916aa8b2bcd84f63",
"build/assets/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/57/68/d03a19b9035cfae7cdc5377d889a",
"build/assets/ba_data/data/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/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",
@ -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/greek.json": "https://files.ballistica.net/cache/ba1/a6/5d/78f912e9a89f98de004405167a6a",
"build/assets/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/88/ee/0cda537bab9ac827def5e236fe1a",
"build/assets/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/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/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",
@ -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/serbian.json": "https://files.ballistica.net/cache/ba1/d7/45/2dd72ac0e51680cb39b5ebaa1c69",
"build/assets/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/27/96/2d53dc3f7dd4e877cd40faafeeef",
"build/assets/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/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/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/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/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/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",
@ -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/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/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/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",
@ -4068,50 +4068,50 @@
"build/assets/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/2d/ef/5335207d41b21b9823f6805997f1",
"build/assets/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/b0/8a/55e2e77623fe657bea24f223a3ae",
"build/assets/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/86/5b/2af4d1e26a1a8073c89acb06e599",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/a8/5e/e644cd4120304fba4d4dbd9762e2",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/92/73/0a1325df721b51d0c9f2e0f6f075",
"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/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/81/5d/8368c53554a9b997f0a1d38c0ced",
"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/release/ballisticakit": "https://files.ballistica.net/cache/ba1/cd/51/6639bbf611e918b21c1676b25764",
"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/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/9b/9f/1e1d79b604749c2033e7fad06394",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/97/f6/2f0e7dba9be2437f43dc4af5e449",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/2e/22/297bedb0cbfb169fb9ba607bff1b",
"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/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/9e/c9/89f8f396ba8597453d81542f6ff6",
"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/release/ballisticakit": "https://files.ballistica.net/cache/ba1/2d/5e/f6e1619a73c21c886425d878b96a",
"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/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/2c/00/fe4d13eb53c0d825da2750b30cec",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/69/19/13f59849fe2a31eac8a350db2e12",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/01/ab/f243ffaa211fd9463cc7ede10f29",
"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/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/b5/1e/bb7075104c420ca1c0663d24768c",
"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/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/25/2f/3bd787d6debb2c4073fd6c2e8098",
"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/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/25/2f/3bd787d6debb2c4073fd6c2e8098",
"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/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/93/1c/1aba110dcf69d8651b428f2927ed",
"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/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/93/1c/1aba110dcf69d8651b428f2927ed",
"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/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/3c/1d/d7864d7822c64ee06cee0dde659e",
"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/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/3c/1d/d7864d7822c64ee06cee0dde659e",
"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/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/47/61/eca0961c54b2eae2cf65fac7848d",
"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/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/47/61/eca0961c54b2eae2cf65fac7848d",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/d3/34/d2fa72d15a085424bad4157a6f2e",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/56/5f/6cde7712eebd76bcd9081b1d063a",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/8e/bb/cde5d48031a147358f49372348fc",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/82/e5/7d8d72481b84b81a3ec2b85cddf1",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/74/11/5059d262beb03fda192c967760ea",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/bf/57/94af76a5f7f51c10e9725730469e",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/fc/56/19374bffec117190ae9c132cff68",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/c6/c9/b6828fe5295e6d5df08fad9ebf3f",
"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/72/f9/d85a330987d81ffc895fc8ec922c",
"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/0c/0e/1b219bc8d0b6d7ccf57bdd721860",
"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/1d/0d/fd0d55be1b0e69de4c4667d34644",
"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/a7/6e/b40ca2ec7dde8c0e9edb0db376c1",
"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/16/31/b64154143f4e903388b9013b41c7",
"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/d0/a0/a9a8c9fe3addcc0a9f7a014acef1",
"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/b4/05/e5a12646d900aeeaa7e974dabda2",
"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/83/6d/d914432abe2d071890a6b3e2d6f1",
"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/0a/13/807d5e92e146b5e9bfc679dbd44b",
"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/9f/28/bf466437892861a399375c864a0d",
"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/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/df/78/f138dbf92a93dcd647831fb8fde4",
"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/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/df/78/f138dbf92a93dcd647831fb8fde4",
"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/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/31/e8/ebc78517b4f6c3dba799d96b6770",
"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/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/31/e8/ebc78517b4f6c3dba799d96b6770",
"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/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/80/f5/1e75ca051bcc9cf5622443368820",
"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/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/80/f5/1e75ca051bcc9cf5622443368820",
"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/libballisticaplus.a": "https://files.ballistica.net/cache/ba1/84/7d/952ba7e47c98635853b6b3e046fa",
"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/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/0d/e3/9a30e693bc57d27a093019988e2d",
"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/76/46/7e4792528fdc5ee7b432b8239567",
"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/35/1b/cd6f88e5a7dda82848362d3ee41e",
"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/7a/10/3c2abaa7fa0280fe5111209a9fd5",
"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/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",
@ -4119,7 +4119,7 @@
"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/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/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"

View File

@ -233,6 +233,8 @@
<w>ballistica's</w>
<w>ballisticakit</w>
<w>ballisticakitcb</w>
<w>ballisticakitso</w>
<w>ballisticaplus</w>
<w>bamaster</w>
<w>bamasteraddr</w>
<w>bamasterlegacy</w>
@ -318,6 +320,7 @@
<w>bmas</w>
<w>bmasl</w>
<w>bmcjphh</w>
<w>bmodfeaturesets</w>
<w>bname</w>
<w>bndl</w>
<w>boffs</w>
@ -522,6 +525,7 @@
<w>clrred</w>
<w>cmakelist</w>
<w>cmakelists</w>
<w>cmakemodular</w>
<w>cmakeserver</w>
<w>cmath</w>
<w>cmathmodule</w>
@ -729,6 +733,7 @@
<w>dingsound</w>
<w>dingsoundhigh</w>
<w>dinl</w>
<w>dir's</w>
<w>dirfilter</w>
<w>dirmanifest</w>
<w>dirname</w>
@ -832,6 +837,7 @@
<w>dusing</w>
<w>dval</w>
<w>dxml</w>
<w>dylibdir</w>
<w>dynload</w>
<w>eachother</w>
<w>eaddrnotavail</w>
@ -894,6 +900,7 @@
<w>enumvalue</w>
<w>enval</w>
<w>envcfg</w>
<w>envglobals</w>
<w>envhash</w>
<w>envname</w>
<w>envs</w>
@ -930,6 +937,7 @@
<w>excludetypes</w>
<w>excstr</w>
<w>exec'ed</w>
<w>exec'ing</w>
<w>execcode</w>
<w>execed</w>
<w>execing</w>
@ -982,6 +990,7 @@
<w>fdata</w>
<w>fdataraw</w>
<w>fdcount</w>
<w>fdcwd</w>
<w>fdesc</w>
<w>fdict</w>
<w>fdirs</w>
@ -1103,6 +1112,8 @@
<w>fsconfigpath</w>
<w>fsdf</w>
<w>fset</w>
<w>fsetmfilenames</w>
<w>fsetmfilenamevals</w>
<w>fsetname</w>
<w>fsets</w>
<w>fsettings</w>
@ -1130,6 +1141,7 @@
<w>fullpath</w>
<w>fullprice</w>
<w>fullscreen</w>
<w>fullstr</w>
<w>fulltest</w>
<w>funcname</w>
<w>funcnames</w>
@ -1403,6 +1415,7 @@
<w>initializers</w>
<w>initialplayerinfos</w>
<w>initing</w>
<w>initname</w>
<w>inits</w>
<w>inittab</w>
<w>inmobi</w>
@ -1419,6 +1432,7 @@
<w>insta</w>
<w>installdir</w>
<w>instancer</w>
<w>instpath</w>
<w>interfacetype</w>
<w>internalmodule</w>
<w>internalsrc</w>
@ -1551,6 +1565,7 @@
<w>lfval</w>
<w>libballistica</w>
<w>libballisticakit</w>
<w>libballisticaplus</w>
<w>libbz</w>
<w>libbzip</w>
<w>libcrypto</w>
@ -1721,6 +1736,7 @@
<w>maxw</w>
<w>maxwait</w>
<w>maxwidth</w>
<w>mbstowcs</w>
<w>mbytecount</w>
<w>mdiv</w>
<w>mdocs</w>
@ -1741,6 +1757,7 @@
<w>metaprogramming</w>
<w>metascan</w>
<w>meteorshower</w>
<w>mfilename</w>
<w>mfpath</w>
<w>mhash</w>
<w>mhbegin</w>
@ -1984,6 +2001,7 @@
<w>olde</w>
<w>oldlady</w>
<w>oldpath</w>
<w>oldpaths</w>
<w>oldtoken</w>
<w>olduuid</w>
<w>olduuids</w>
@ -2003,7 +2021,9 @@
<w>opposingbody</w>
<w>opposingnode</w>
<w>opstr</w>
<w>optnm</w>
<w>optparse</w>
<w>optstuff</w>
<w>orchestrahitsound</w>
<w>origwrapper</w>
<w>ortho</w>
@ -2019,6 +2039,7 @@
<w>ourhash</w>
<w>ourname</w>
<w>ourpackage</w>
<w>ourpaths</w>
<w>ourself</w>
<w>outdata</w>
<w>outdelay</w>
@ -2065,6 +2086,7 @@
<w>pathbar</w>
<w>pathcapture</w>
<w>pathdst</w>
<w>pathlen</w>
<w>pathlib</w>
<w>pathlist</w>
<w>pathnames</w>
@ -2357,8 +2379,10 @@
<w>pythondontwritebytecode</w>
<w>pythonenumsmodule</w>
<w>pythonhashseed</w>
<w>pythonoptimize</w>
<w>pythonpath</w>
<w>pythonpaths</w>
<w>pythonutf</w>
<w>pythonw</w>
<w>pytree</w>
<w>pytz</w>
@ -2390,6 +2414,8 @@
<w>readexactly</w>
<w>readline</w>
<w>readlines</w>
<w>readlink</w>
<w>readlinkat</w>
<w>realpath</w>
<w>realsies</w>
<w>recache</w>
@ -2708,10 +2734,12 @@
<w>sred</w>
<w>sriyakaal</w>
<w>sshd</w>
<w>ssize</w>
<w>sslcontext</w>
<w>sslproto</w>
<w>ssval</w>
<w>stackstr</w>
<w>stager</w>
<w>standin</w>
<w>starscale</w>
<w>startercache</w>
@ -2820,6 +2848,7 @@
<w>syncitem</w>
<w>syncitems</w>
<w>synclist</w>
<w>syscall</w>
<w>sysconfigdata</w>
<w>sysctl</w>
<w>syslogmodule</w>
@ -3186,6 +3215,7 @@
<w>winapi</w>
<w>winbeast</w>
<w>wincfg</w>
<w>wincfglc</w>
<w>wincount</w>
<w>winempty</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!)
- 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 \
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 \
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
@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 $@
# 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 \
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 \
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
@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 $@
# 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
@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 $@
# 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
@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 $@
# 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 \
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 \
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
@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 $@
# 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 \
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 \
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
@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 $@
# 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
@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 $@
# 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
@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 $@
# 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) \
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/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 \
assets-windows-$(WINPLAT_X86) \
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/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 \
assets-windows-$(WINPLAT_X86) \
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/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 \
assets-windows-$(WINPLAT_X86) \
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/dist/BallisticaKitHeadless.exe: .efrocachemap
@ -931,7 +931,7 @@ WINDOWS_CONFIGURATION ?= Debug
# Stage assets and other files so a built binary will run.
windows-staging: assets-windows resources meta
$(STAGE_ASSETS) -win-$(WINPLT)-$(WINCFG) \
$(STAGE_ASSETS) -win-$(WINPLT) -$(WINCFGLC) \
build/windows/$(WINCFG)_$(WINPLT)
# Build and run a debug windows build (from WSL).
@ -1026,7 +1026,7 @@ cmake-lldb: cmake-build
# Build but don't run it.
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)
cmake-binary: meta
@ -1046,25 +1046,43 @@ cmake-server: cmake-server-build
cmake-server-build: assets-server meta cmake-server-binary
@$(STAGE_ASSETS) -cmakeserver -$(CM_BT_LC) build/cmake/server-$(CM_BT_LC)
@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
@tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC)/dist
@cd build/cmake/server-$(CM_BT_LC)/dist && test -f Makefile \
|| cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true \
$(shell pwd)/ballisticakit-cmake
@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:
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.
clion-staging: assets-cmake resources meta
$(STAGE_ASSETS) -cmake build/clion_debug
$(STAGE_ASSETS) -cmake build/clion_release
$(STAGE_ASSETS) -cmake -debug build/clion_debug
$(STAGE_ASSETS) -cmake -release build/clion_release
# Tell make which of these targets don't represent files.
.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)
WINPLT = $(WINDOWS_PLATFORM)
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.
ballisticakit-cmake/.clang-format: .clang-format

View File

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

View File

@ -177,6 +177,12 @@ add_library(ode
)
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
# collisions would fail randomly, leading to characters falling through
# 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 ()
# BallisticaKit binary.
add_executable(ballisticakit
set(BALLISTICA_SOURCES
${BA_SRC_ROOT}/external/qr_code_generator/QrCode.cpp
# AUTOGENERATED_PUBLIC_BEGIN (this section is managed by the "update_project" tool)
${BA_SRC_ROOT}/ballistica/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.h
# AUTOGENERATED_PUBLIC_END
)
)
# BallisticaKit monolithic binary.
add_executable(ballisticakit ${BALLISTICA_SOURCES})
# Gets -rdynamic added when linking gcc builds which exports all symbols
# which gives us more meaningful stack traces using backtrace_symbols().
set_target_properties(ballisticakit PROPERTIES ENABLE_EXPORTS 1)
if (HEADLESS)
set_target_properties(ballisticakit PROPERTIES OUTPUT_NAME "ballisticakit_headless")
set_target_properties(ballisticakit
PROPERTIES OUTPUT_NAME "ballisticakit_headless")
endif ()
target_include_directories(ballisticakit PRIVATE
${Python_INCLUDE_DIRS}
${BA_SRC_ROOT}/external/open_dynamics_engine-ef
${EXTRA_INCLUDE_DIRS}
)
${EXTRA_INCLUDE_DIRS})
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)
# Hack for building on rpi (might be due to my manually built Python 3.8)
# Hopefully can remove later...
# Hack for building on rpi; need to update my pi so I can remove this.
if(EXISTS "/home/pi")
target_link_libraries(ballisticakit PRIVATE dl util stdc++fs)
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.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
# namespace scheme.

View File

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

View File

@ -12,6 +12,6 @@ from batools.featureset import FeatureSet
# Grab the FeatureSet we should apply to.
fset = FeatureSet.get_active()
fset.has_native_python_module = False
fset.has_python_binary_module = False
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.
if debug_build != sys.flags.dev_mode:
logging.warning(
'Mismatch in ballistica debug_build %s'
' and sys.flags.dev_mode %s; this may cause problems.',
'Ballistica was built with debug-mode %s'
' but Python is running with dev-mode %s;'
' this mismatch may cause problems.'
' See https://docs.python.org/3/library/devmode.html',
debug_build,
sys.flags.dev_mode,
)
@ -75,11 +77,11 @@ def setup_env_for_app_run() -> None:
assert baenv.config_exists()
# If we were unable to set paths earlier, complain now.
if baenv.g_paths_set_failed:
if baenv.did_paths_set_fail():
logging.warning(
'Ballistica Python paths have not been set. This may cause'
' problems. To ensure paths are set, run baenv.configure()'
' before importing any ballistica modules.'
' BEFORE importing any Ballistica modules.'
)
# Set up interrupt-signal handling.
@ -144,9 +146,10 @@ def on_app_launching() -> None:
assert _babase.in_logic_thread()
# 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(
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),
)

View File

@ -267,6 +267,9 @@ class StoreSubsystem:
'icons.mikirog': {
'icon': babase.charstr(babase.SpecialChar.MIKIROG)
},
'icons.explodinary': {
'icon': babase.charstr(babase.SpecialChar.EXPLODINARY_LOGO)
},
}
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
before running a ballistica app. This includes things such as paths,
logging, debug-modes, garbage-collection settings, and signal handling.
Because these things are global in nature, this should be done before
any ballistica modules are imported.
logging, and app-dirs. Because these things are global in nature, this
should be done before 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
order to integrate it in arbitrary Python environments, but this may
@ -20,25 +22,42 @@ import logging
from pathlib import Path
from dataclasses import dataclass
from typing import TYPE_CHECKING
import __main__
from efro.log import setup_logging, LogLevel
if TYPE_CHECKING:
from efro.log import LogHandler
# IMPORTANT - It is likely (and in some cases expected) that this
# module's code will be exec'ed multiple times. This is because it is
# the job of this module to set up paths for an engine run, and that may
# involve modifying sys.path in such a way that this module resolves to
# a different path afterwards (for example from
# /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
# using.
TARGET_BALLISTICA_BUILD = 21171
TARGET_BALLISTICA_VERSION = '1.7.23'
_g_env_config: EnvConfig | None = None
g_paths_set_failed = False # pylint: disable=invalid-name
g_user_system_scripts_dir: str | None = None
TARGET_BALLISTICA_BUILD = 21183
TARGET_BALLISTICA_VERSION = '1.7.24'
@dataclass
class EnvConfig:
"""Final settings put together by the configure call."""
"""Environment put together by the configure call."""
config_dir: str
data_dir: str
@ -49,17 +68,56 @@ class EnvConfig:
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:
"""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:
"""Return the active env-config. Creates default if none exists."""
if _g_env_config is None:
"""Return the active config, creating a default if none exists."""
envglobals = EnvGlobals.get()
if not envglobals.config_called:
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(
@ -72,22 +130,91 @@ def configure(
) -> None:
"""Set up the Python environment for running a ballistica app.
This includes things such as Python paths and log redirection. For
that reason, this should be called before any other ballistica
modules are imported, since it may make changes to sys.path,
affecting where those modules get loaded from.
This includes things such as Python path wrangling and app directory
creation. This should be called before any other ballistica modules
are imported since it may make changes to sys.path which can affect
where those modules get loaded from.
"""
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
global _g_env_config # pylint: disable=global-statement
if _g_env_config is not None:
raise RuntimeError('An EnvConfig has already been created.')
envglobals = EnvGlobals.get()
# The very first thing we do is set up our logging system and feed
# 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.
if envglobals.config_called:
raise RuntimeError(
'baenv.configure() has already been called;'
' 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_path=None,
level=LogLevel.DEBUG,
@ -95,41 +222,46 @@ def configure(
log_stdout_stderr=True,
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,
# mods, etc. are pulled from predictable places.
cwd_path = Path.cwd()
def _setup_certs(contains_python_dist: bool) -> None:
# In situations where we're bringing our own Python let's also
# 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
# imports:
# Let both OpenSSL and requests (if present) know to use this.
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.
if data_dir is None:
assert Path(__file__).parts[-3:-1] == ('ba_data', 'python')
data_dir_path = Path(__file__).parents[2]
# Prefer tidy relative paths like '.' if possible.
data_dir = str(
data_dir_path.relative_to(cwd_path)
if data_dir_path.is_relative_to(cwd_path)
else data_dir_path
)
def _setup_paths(
user_python_dir: str | None,
app_python_dir: str | None,
site_python_dir: str | None,
data_dir: str | None,
config_dir: str | None,
) -> tuple[str | None, str | None, str | None, str, str, str]:
# First a few paths we can ALWAYS calculate since they don't affect
# Python imports:
envglobals = EnvGlobals.get()
data_dir = _calc_data_dir(data_dir)
# Default config-dir is simply ~/.ballisticakit
if config_dir is None:
config_dir = str(Path(Path.home(), '.ballisticakit'))
# Ok now Python paths.
# By default, app-python-dir is simply ba_data/python under
# data-dir.
# Standard app-python-dir is simply ba_data/python under data-dir.
standard_app_python_dir = str(Path(data_dir, 'ba_data', 'python'))
# If _babase has already been imported, there's not much we can do
@ -137,12 +269,11 @@ def configure(
if '_babase' in sys.modules:
app_python_dir = user_python_dir = site_python_dir = None
# We don't actually complain yet here; we simply take note
# that we weren't able to set paths. Then we complain if/when
# the app is started. This way, non-app uses of babase won't be
# filled with unnecessary warnings.
global g_paths_set_failed # pylint: disable=global-statement
g_paths_set_failed = True
# We don't actually complain yet here; we simply take note that
# we weren't able to set paths. Then we complain if/when the app
# is started. This way, non-app uses of babase won't be filled
# with unnecessary warnings.
envglobals.paths_set_failed = True
else:
# 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
# under it where FOO matches our version, use that as our
# app_python_dir.
check_dir = os.path.join(
user_python_dir, 'sys', TARGET_BALLISTICA_VERSION
)
if os.path.isdir(check_dir):
global g_user_system_scripts_dir # pylint: disable=global-statement
g_user_system_scripts_dir = check_dir
app_python_dir = check_dir
# app_python_dir. This allows modding built-in stuff on
# platforms where there is no write access to said built-in
# stuff.
check_dir = Path(user_python_dir, 'sys', TARGET_BALLISTICA_VERSION)
if check_dir.is_dir():
envglobals.user_system_scripts_dir = app_python_dir = str(check_dir)
# Ok, now apply these to sys.path.
# First off, strip out any instances of the path containing this
# module. We will probably be re-adding the same path in a
# moment but its technically possible that we won't be (if
# app_python_dir is overridden to somewhere else, etc.)
# module. We will *probably* be re-adding the same path in a
# moment so this keeps things cleaner. Though hmm should we
# leave it in there in cases where we *don't* re-add the same
# path?...
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
]
# 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
# of the world if we fail though.
# Let's place mods first (so users can override whatever they
# 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]] = [
('config', config_dir),
('user_python', user_python_dir),
@ -201,32 +355,22 @@ def configure(
try:
os.makedirs(cdir, exist_ok=True)
except Exception:
# Not the end of the world if we can't make these dirs.
logging.warning(
"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
# also 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
def _main() -> None:
# Run a default configure BEFORE importing babase.
# (may affect where babase comes from).
configure()
# Let both OpenSSL and requests (if present) know to use this.
os.environ['SSL_CERT_FILE'] = os.environ[
'REQUESTS_CA_BUNDLE'
] = certifi.where()
import babase
babase.app.run()
# 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();
// 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
// (though we don't explicitly ask anyone to apply it until later).
python->ReadConfig();
@ -280,6 +285,10 @@ void BaseFeatureSet::RunAppToCompletion() {
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
// loop until the app is quit.
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
// base is fully imported.
if (!IsBaseCompletelyImported()) {
printf(
"WARNING: V1CloudLog called before babase fully imported; ignoring.\n");
static bool warned = false;
if (!warned) {
warned = true;
printf(
"WARNING: V1CloudLog called before babase fully imported; "
"ignoring.\n");
}
return;
}
@ -523,7 +537,11 @@ void BaseFeatureSet::DoV1CloudLog(const std::string& msg) {
// Need plus for direct sends.
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;
}

View File

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

View File

@ -97,7 +97,7 @@ void CoreFeatureSet::PostInit() {
// FIXME: MOVE THIS TO A RUN_APP_TO_COMPLETION() SORT OF PLACE.
// For now it does the right thing here since all we have is monolithic
// builds but this will need to account for more situations later.
python->ReleaseMainThreadGIL();
// python->ReleaseMainThreadGIL();
}
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() {
auto gil{Python::ScopedInterpreterLock()};
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);
}
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

View File

@ -52,11 +52,8 @@ class CorePython {
/// logging is available, logs locally using Logging::DisplayLog()
/// (with an added warning).
void LoggingCall(LogLevel loglevel, const std::string& msg);
void AcquireGIL();
void ReleaseGIL();
void ImportPythonObjs();
void VerifyPythonEnvironment();
void ReleaseMainThreadGIL();
void SoftImportBase();
const auto& objs() { return objs_; }
@ -64,8 +61,6 @@ class CorePython {
private:
PythonObjectSet<ObjID> objs_;
PyThreadState* logic_thread_state_{};
// 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.
bool python_logging_calls_enabled_{};

View File

@ -2,5 +2,5 @@
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
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.

View File

@ -385,16 +385,18 @@ void ConnectionToClient::HandleMessagePacket(
case BA_MESSAGE_CLIENT_INFO: {
if (buffer.size() > 1) {
// Make a null-terminated copy of the string data.
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;
cJSON* info = cJSON_Parse(reinterpret_cast<const char*>(&(buffer[1])));
cJSON* info = cJSON_Parse(str_buffer.data());
if (info) {
cJSON* b = cJSON_GetObjectItem(info, "b");
if (b) {
build_number_ = b->valueint;
} 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
@ -403,7 +405,7 @@ void ConnectionToClient::HandleMessagePacket(
if (t) {
token_ = t->valuestring;
} 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
@ -423,9 +425,9 @@ void ConnectionToClient::HandleMessagePacket(
cJSON_Delete(info);
} else {
Log(LogLevel::kError,
"got invalid json in clientinfo message: '"
"Got invalid json in clientinfo message: '"
+ std::string(reinterpret_cast<const char*>(&(buffer[1])))
+ "'");
+ "'.");
}
}
got_client_info_ = true;

View File

@ -22,7 +22,7 @@
#endif
// 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 core_config =
ballistica::core::CoreConfig::FromCommandLineAndEnv(argc, argv);
@ -39,8 +39,10 @@ auto main(int argc, char** argv) -> int {
namespace ballistica {
// These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 21171;
const char* kEngineVersion = "1.7.23";
const int kEngineBuildNumber = 21183;
const char* kEngineVersion = "1.7.24";
#if BA_MONOLITHIC_BUILD
auto MonolithicMain(const core::CoreConfig& core_config) -> int {
// 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.
}
#endif // BA_MONOLITHIC_BUILD
void FatalError(const std::string& message) {
// Let the user and/or master-server know we're dying.
FatalError::ReportFatalError(message, false);

View File

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

View File

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

View File

@ -23,8 +23,10 @@ namespace ballistica {
// can override any of these before this is included.
// Monolithic builds consist of a single binary that inits and manages
// Python itself, as opposed to modular builds which are made up of
// Python binary modules which are run under a standard Python runtime.
// Python itself, as opposed to modular builds which are made up of Python
// 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
#define BA_MONOLITHIC_BUILD 1
#endif

View File

@ -7,6 +7,7 @@
#include "ballistica/core/support/base_soft.h"
#include "ballistica/shared/foundation/fatal_error.h"
#include "ballistica/shared/python/python.h"
#include "ballistica/shared/python/python_sys.h"
namespace ballistica {
@ -224,7 +225,7 @@ void EventLoop::WaitForNextEvent(bool single_cycle) {
// While we're waiting, allow other python threads to run.
if (acquires_python_gil_) {
g_core->python->ReleaseGIL();
ReleaseGIL();
}
// 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_) {
g_core->python->AcquireGIL();
AcquireGIL();
}
}
@ -451,7 +452,7 @@ void EventLoop::SetAcquiresPythonGIL() {
assert(!acquires_python_gil_); // This should be called exactly once.
assert(ThreadIsCurrent());
acquires_python_gil_ = true;
g_core->python->AcquireGIL();
AcquireGIL();
}
// Explicitly kill the main thread.
@ -784,4 +785,30 @@ auto EventLoop::CheckPushRunnableSafety() -> bool {
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

View File

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

View File

@ -377,21 +377,16 @@ void Python::MarkReachedEndOfModule(PyObject* module) {
class Python::ScopedInterpreterLock::Impl {
public:
Impl() {
if (need_lock_) {
// Grab the python GIL.
gstate_ = PyGILState_Ensure();
}
// Grab the python GIL.
gil_state_ = PyGILState_Ensure();
}
~Impl() {
if (need_lock_) {
// Release the python GIL.
PyGILState_Release(gstate_);
}
// Release the python GIL.
PyGILState_Release(gil_state_);
}
private:
bool need_lock_{true};
PyGILState_STATE gstate_{PyGILState_UNLOCKED};
PyGILState_STATE gil_state_{PyGILState_UNLOCKED};
};
Python::ScopedInterpreterLock::ScopedInterpreterLock()
@ -401,6 +396,31 @@ Python::ScopedInterpreterLock::ScopedInterpreterLock()
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
// objects' dir() results)

View File

@ -39,9 +39,9 @@ class Python {
BA_DISALLOW_CLASS_COPIES(ScopedCallLabel);
};
/// Use this to protect Python code that may be run in cases where we don't
/// hold the Global Interpreter Lock (GIL) (basically anything outside of the
/// logic thread).
/// Use this to protect Python code that may be run in cases where we
/// don't hold the Global Interpreter Lock (GIL). (Basically anything
/// outside of the logic thread).
class ScopedInterpreterLock {
public:
ScopedInterpreterLock();
@ -55,7 +55,20 @@ class Python {
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.
/// 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:
pass
# Suffix for the pyc files we include in stagings.
# We're using 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
# will be ignored.
# Suffix for the pyc files we include in stagings. We're using
# 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 will be ignored.
OPT_PYC_SUFFIX = 'cpython-' + PYVER.replace('.', '') + '.opt-1.pyc'
class Config:
"""Encapsulates command options."""
def stage_assets(projroot: str, args: list[str] | None = None) -> None:
"""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:
self.projroot = projroot
# 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.serverdst: str | None = None
self.win_extras_src: str | None = None
self.win_platform: 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_meshes = True
self.include_collision_meshes = True
@ -51,11 +63,105 @@ class Config:
self.is_payload_full = False
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:
# On Android we get nitpicky with what
# we want to copy in since we can speed up
# iterations by installing stripped down
# apks.
# On Android we get nitpicky with exactly what we want to copy
# in since we can speed up iterations by installing stripped
# down apks.
self.dst = 'assets/ballistica_files'
self.pylib_src_name = 'pylib-android'
self.include_payload_file = True
@ -98,9 +204,9 @@ class Config:
elif arg == '-audio':
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."""
winempty, wintype, winplt, wincfg = platform.split('-')
winempty, wintype, winplt = platform.split('-')
self.win_platform = winplt
self.win_type = wintype
assert winempty == ''
@ -115,78 +221,375 @@ class Config:
self.include_audio = False
self.include_meshes = False
else:
raise RuntimeError(f'Invalid wintype: "{wintype}"')
raise RuntimeError(f"Invalid wintype: '{wintype}'.")
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':
self.win_extras_src = self.projroot + '/build/assets/windows/x64'
self.win_extras_src = f'{self.projroot}/build/assets/windows/x64'
else:
raise RuntimeError(f'Invalid winplt: "{winplt}"')
raise RuntimeError(f"Invalid winplt: '{winplt}'.")
if wincfg == 'Debug':
self.debug = True
elif wincfg == 'Release':
self.debug = False
def _sync_windows_extras(self) -> None:
# pylint: disable=too-many-branches
assert self.win_extras_src is not None
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:
raise RuntimeError(f'Invalid wincfg: "{wincfg}"')
pyd_rules = ['--exclude', '*_d.pyd', '--include', '*.pyd']
def parse_args(self, args: list[str]) -> None:
"""Parse args and apply to the cfg."""
if len(args) < 1:
raise RuntimeError('Expected a platform argument.')
platform = args[0]
if platform == '-android':
self._parse_android_args(args)
elif platform.startswith('-win'):
self._parse_win_platform(platform, args)
elif platform == '-cmake':
self.dst = args[1]
self.tex_suffix = '.dds'
elif '-cmakeserver' in args:
self.dst = os.path.join(args[-1], 'dist')
self.serverdst = args[-1]
self.include_textures = False
self.include_audio = False
self.include_meshes = False
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
os.makedirs(f'{self.dst}/{dstdirname}', exist_ok=True)
cmd: list[str] = (
[
'rsync',
'--recursive',
'--times',
'--delete',
'--delete-excluded',
'--prune-empty-dirs',
'--include',
'*.ico',
'--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.
# FIXME: should require this for all platforms for consistency.
if '-debug' in args:
self.debug = True
assert '-release' not in args
elif '-release' in args:
self.debug = False
# 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 self.debug else ''
# Note: Needs updating when Python version changes (currently 3.11).
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:
raise RuntimeError(
"Expected either '-debug' or '-release' in args."
)
elif '-xcode-mac' in args:
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 '-xcode-ios' in args:
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'
toplevelfiles += [
'msvcp140d.dll',
'vcruntime140d.dll',
'ucrtbased.dll',
]
# Include the runtime redistributables in release builds.
if not self.debug:
if self.win_platform == 'x64':
toplevelfiles.append('vc_redist.x64.exe')
elif self.win_platform == 'Win32':
toplevelfiles.append('vc_redist.x86.exe')
else:
raise RuntimeError(f'Invalid win_platform {self.win_platform}')
cmd2 = (
['rsync', '--times']
+ [os.path.join(self.win_extras_src, f) for f in toplevelfiles]
+ [f'{self.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 {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:
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:
"""Generate an md5sum given a filename."""
def _filehash(filename: str) -> str:
"""Generate a hash for a file."""
md5 = hashlib.md5()
with open(filename, mode='rb') as infile:
for buf in iter(partial(infile.read, 1024), b''):
@ -194,18 +597,9 @@ def md5sum(filename: str) -> str:
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:
if not assets_root.endswith('/'):
assets_root = assets_root + '/'
assets_root = f'{assets_root}/'
# Now construct a payload file if we have any files.
file_list = []
@ -222,226 +616,24 @@ def _write_payload_file(assets_root: str, full: bool) -> None:
raise RuntimeError(
f"Invalid filename (contains spaces): '{fpathshort}'"
)
payload_str += fpathshort + ' ' + md5sum(fpath) + '\n'
payload_str += f'{fpathshort} {_filehash(fpath)}\n'
file_list.append(fpathshort)
payload_path = assets_root + '/payload_info'
payload_path = f'{assets_root}/payload_info'
if file_list:
# Write the file count, whether this is a 'full' payload, and finally
# the file list.
payload_str = (
str(len(file_list))
+ '\n'
+ ('1' if full else '0')
+ '\n'
+ payload_str
)
# Write the file count, whether this is a 'full' payload, and
# finally the file list.
fullstr = '1' if full else '0'
payload_str = f'{len(file_list)}\n{fullstr}\n{payload_str}'
with open(payload_path, 'w', encoding='utf-8') as outfile:
outfile.write(payload_str)
else:
# Remove the payload file; this will cause the game to completely
# skip the payload processing step.
# Remove the payload file; this will cause the game to
# completely skip the payload processing step.
if os.path.exists(payload_path):
os.unlink(payload_path)
def _sync_windows_extras(cfg: Config) -> None:
# 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(
path: str, contents: str, make_executable: bool = False
) -> None:
@ -459,7 +651,7 @@ def _write_if_changed(
subprocess.run(['chmod', '+x', path], check=True)
def stage_server_file(
def _stage_server_file(
projroot: str, mode: str, infilename: str, outfilename: str
) -> None:
"""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')
else:
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.
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]
builddir = 'build/dummymodules'

View File

@ -54,7 +54,7 @@ class FeatureSet:
# its C++ code. The build process will try to create dummy
# modules for all native modules, so to avoid errors you must
# 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
# 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:
"""Stage assets for a build."""
from batools.assetstaging import main
import batools.assetstaging
from efro.error import CleanError
try:
main(projroot=str(PROJROOT), args=sys.argv[2:])
batools.assetstaging.stage_assets(
projroot=str(PROJROOT), args=sys.argv[2:]
)
except CleanError as exc:
exc.pretty_print()
sys.exit(1)

View File

@ -25,16 +25,48 @@ def gen_monolithic_register_modules() -> None:
featuresets = FeatureSet.get_all_for_project(str(PROJROOT))
# 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)
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(
f'auto PyInit_{n}() -> PyObject*;' for n in pymodulenames
f'auto {initname(n)}() -> PyObject*;' for n in pymodulenames
)
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 = """
// 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.
#include "ballistica/shared/ballistica.h"
#include "ballistica/shared/python/python_sys.h"
#if BA_MONOLITHIC_BUILD
extern "C" {
${EXTERN_DEF_CODE}
}
#endif // BA_MONOLITHIC_BUILD
namespace ballistica {
@ -58,15 +89,15 @@ def gen_monolithic_register_modules() -> None:
/// binary modules get located as .so files on disk as per regular
/// Python behavior.
void MonolithicRegisterPythonModules() {
#if BA_MONOLITHIC_BUILD
if (g_buildconfig.monolithic_build()) {
${PY_REGISTER_CODE}
#else
FatalError(
"MonolithicRegisterPythonModules should not be called"
" in modular builds.");
#endif // BA_MONOLITHIC_BUILD
} else {
FatalError(
"MonolithicRegisterPythonModules should not be called"
" in modular builds.");
}
}
${PY_INIT_PLUS}
} // namespace ballistica
#endif // BALLISTICA_CORE_MGEN_PYTHON_MODULES_MONOLITHIC_H_
@ -74,7 +105,10 @@ def gen_monolithic_register_modules() -> None:
out = (
textwrap.dedent(base_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()
+ '\n'
)
@ -84,19 +118,6 @@ def gen_monolithic_register_modules() -> None:
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:
"""Run a python examination at a given point in a given file."""
import os
@ -244,7 +265,7 @@ def update_cmake_prefab_lib() -> None:
)
suffix = '_server' if buildtype == 'server' else '_gui'
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
@ -252,7 +273,7 @@ def update_cmake_prefab_lib() -> None:
subprocess.run(['make', target], check=True)
libdir = os.path.join(builddir, 'prefablib')
libpath = os.path.join(libdir, 'libballistica_plus.a')
libpath = os.path.join(libdir, 'libballisticaplus.a')
update = True
time1 = os.path.getmtime(target)

View File

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

View File

@ -714,42 +714,77 @@ def _patch_py_wreadlink_test() -> None:
fname = 'Python/fileutils.c'
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,
' res = 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'
),
' res = (int)readlink(cpath, cbuf, cbuf_len);\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=%X'
' 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 */"
),
)
# Verbose problem exploration:
# txt = replace_exact(
# txt,
# '#include <stdlib.h> // mbstowcs()\n',
# '#include <stdlib.h> // mbstowcs()\n'
# '#include <sys/syscall.h>\n',
# )
# txt = replace_exact(txt, ' Py_ssize_t res;\n', '')
# 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)

View File

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