mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-24 07:53:30 +08:00
work on cmake-modular builds
This commit is contained in:
parent
15d9d1c7ce
commit
aeb893294d
104
.efrocachemap
generated
104
.efrocachemap
generated
@ -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"
|
||||
|
||||
30
.idea/dictionaries/ericf.xml
generated
30
.idea/dictionaries/ericf.xml
generated
@ -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>
|
||||
|
||||
36
CHANGELOG.md
36
CHANGELOG.md
@ -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!)
|
||||
|
||||
75
Makefile
75
Makefile
@ -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
|
||||
|
||||
29
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
29
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
@ -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>
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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'}
|
||||
|
||||
@ -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'}
|
||||
|
||||
@ -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),
|
||||
)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_{};
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
6
src/external/readlinktest.c
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
printf("HELLO WORLD!\n");
|
||||
return 0;
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user