mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-06 15:47:06 +08:00
new high-level feature-set copy/delete functionality
This commit is contained in:
parent
b51bc29773
commit
0709e553d7
88
.efrocachemap
generated
88
.efrocachemap
generated
@ -4064,50 +4064,50 @@
|
|||||||
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
||||||
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
||||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "4542f7820b33b8f1f6719b17efa26453",
|
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "3403caf882f5efc1c5a62bf452994bd1",
|
||||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "c94898207acb63e3e09cb08b50ebd287",
|
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "c046dcf69b1d3cb122869ee1f8df06d6",
|
||||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "ad606ee2ee1367b906c9cbb18c53baf6",
|
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "10f90e814342ba8553c193d8ce3221d1",
|
||||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "776e2461a852753010278d5b90ff32df",
|
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "2827cb64562372b70fe78c30cc4dbf1e",
|
||||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "aefcfd8774114e7cebc418d0adad56f2",
|
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "37e25714c6b19f5edc1135820edb0ef4",
|
||||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "d21df3fc06db87786d68ccc1417d043e",
|
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "bacec90936f644c739eb9230b61c1528",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "7b218f79079e8e0d92b5f0a4afb0599d",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "51e044f01c1f783f2c88d8ba490370a6",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "94738f2f6fcbea9dad60af4bd6a7cd5d",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "01aff77ee4c84b06b54664e26aaed0cf",
|
||||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "033b39b34a10d5bce6e53572a816d0ef",
|
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "7430ba5eadfdd15310d0b140d5ef3f2b",
|
||||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "f4eb1cc72a16eafcaba2d55c65f19a7b",
|
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "de88562b3c51a56a5a89bc35a7888e58",
|
||||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "fec5b1818aa97bc0dff1ddf127742574",
|
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "74b6f29023a4a3e90b2233d77c0c38bb",
|
||||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "76930acbbd2e8dd35f35639d85ce21ac",
|
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "78150d99f0e8dfd2f6785af4335b3f49",
|
||||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "d5ab5ad85dd8d113125d15f03c221db3",
|
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "ccc2f72a1a12a3314f6ffea3ea20875c",
|
||||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "29fbcf76221d71ea3ecb73d8ab353f7b",
|
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "bab389beb2e52641e5a7e5cf9a62bf69",
|
||||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "3d8b4b5d6ba376f2d280209e0aa3bcf2",
|
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "a3de45a3355c610719a477077babf451",
|
||||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "fb9da4455aa7c0d8e5120a75ccaeabcb",
|
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "cf35da279c2ff3d4a8241e51199fea5d",
|
||||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "056f8137ba8b1179b66eea59944aefb2",
|
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "8fcb6c2f3be27b2aadee60a436ee5c82",
|
||||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "78f53224dd6052c93da31bda7ee1c84c",
|
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "695c693d94935c99e3990c885b882091",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "82128374a7eabc651061d778e099b923",
|
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "38a69802cca5b4bc3a344777f12679bd",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "2cd60cbebfbe25447791284b42c3caf9",
|
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "4e24b9c6b980844de8c482dd1034fb97",
|
||||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "a589af5b31246539eac3264c829c41a0",
|
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "a3607fd941915ab11503f82acfc392b5",
|
||||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "3dfaf945474294cb9f3808a835fb667c",
|
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "b5a129d83796c9e7015ab5e319d2c22f",
|
||||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "a589af5b31246539eac3264c829c41a0",
|
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "a3607fd941915ab11503f82acfc392b5",
|
||||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "3dfaf945474294cb9f3808a835fb667c",
|
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "b5a129d83796c9e7015ab5e319d2c22f",
|
||||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "47e08d2f265f4dda15b309fa67ba163b",
|
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "13405a4a16a71d073b6b3cabbbcd9666",
|
||||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "c9a5225be07b4456e073014e1db2cafe",
|
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "86b26dc84cc7fa7095e51cfcae759c0b",
|
||||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "47e08d2f265f4dda15b309fa67ba163b",
|
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "13405a4a16a71d073b6b3cabbbcd9666",
|
||||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "c9a5225be07b4456e073014e1db2cafe",
|
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "86b26dc84cc7fa7095e51cfcae759c0b",
|
||||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "f79382e5342db6f38f4c07170589d62d",
|
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "678e09ecd5da367ce290ca7318617b61",
|
||||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "b2d5386301891813a790f1a19d442022",
|
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "a9cdc9dd029dabc6dfa5b61d33de7927",
|
||||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "f79382e5342db6f38f4c07170589d62d",
|
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "678e09ecd5da367ce290ca7318617b61",
|
||||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "b2d5386301891813a790f1a19d442022",
|
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "a9cdc9dd029dabc6dfa5b61d33de7927",
|
||||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "899eda04958efce6903b7dd2abe6c76f",
|
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "4811585805942428ddb217917e4ad843",
|
||||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "e98d76fe2d0af7e775801998d8591340",
|
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "c5c40967e63471c9c4abd6dfbef892df",
|
||||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "e9d551c0bfbb330470b1e0784028e4d3",
|
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "d34c0a142e7d391a109a33ea3cc77c08",
|
||||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "e98d76fe2d0af7e775801998d8591340",
|
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "c5c40967e63471c9c4abd6dfbef892df",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "77f25ad3348eb212969725c0ec7ebec8",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "4eb48f28a678a7f2eae8c10d4d86b879",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "df8038790ce73124950dc443c1e972ad",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "675e12e534ebec6cb9760b066c158747",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "f184798b7973343cdc42d16e05aa335f",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "5d9bb2f2835069e186418b1b02598168",
|
||||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "2e3ed4ea52261efd17d0927b21cf4075",
|
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "7fa0439993cdd80f098a2cf37d4e6b31",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "1a5c374cfdd07ccbb2f1e9a44b886131",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "1bac9e9d670f8dfac75398085820d039",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "66da72816faa1d87d0b3fe677c6eb9c8",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "9ecb0b936f758250417f7c014f89d683",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "fbef69c5fba9b7c94d37e233eb6c9642",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "912935f68da6dfca6312b3859c14ee27",
|
||||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "c37e1dc4f95a8db0b5059dae0b5f5241",
|
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "aa9ca81cff1cd3135af6fa81cb16851a",
|
||||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
|
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
|
||||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "ad347097a38e0d7ede9eb6dec6a80ee9",
|
"src/ballistica/base/mgen/pyembed/binding_base.inc": "ad347097a38e0d7ede9eb6dec6a80ee9",
|
||||||
|
|||||||
7
.idea/dictionaries/ericf.xml
generated
7
.idea/dictionaries/ericf.xml
generated
@ -823,6 +823,7 @@
|
|||||||
<w>dstent</w>
|
<w>dstent</w>
|
||||||
<w>dstfile</w>
|
<w>dstfile</w>
|
||||||
<w>dstfin</w>
|
<w>dstfin</w>
|
||||||
|
<w>dstfs</w>
|
||||||
<w>dstjson</w>
|
<w>dstjson</w>
|
||||||
<w>dstlines</w>
|
<w>dstlines</w>
|
||||||
<w>dstname</w>
|
<w>dstname</w>
|
||||||
@ -1085,6 +1086,7 @@
|
|||||||
<w>flycheck</w>
|
<w>flycheck</w>
|
||||||
<w>fmod</w>
|
<w>fmod</w>
|
||||||
<w>fname</w>
|
<w>fname</w>
|
||||||
|
<w>fnamefilt</w>
|
||||||
<w>fnamefull</w>
|
<w>fnamefull</w>
|
||||||
<w>fnames</w>
|
<w>fnames</w>
|
||||||
<w>fnmatch</w>
|
<w>fnmatch</w>
|
||||||
@ -2669,6 +2671,7 @@
|
|||||||
<w>shobs</w>
|
<w>shobs</w>
|
||||||
<w>shortname</w>
|
<w>shortname</w>
|
||||||
<w>shouldn</w>
|
<w>shouldn</w>
|
||||||
|
<w>shouldnt</w>
|
||||||
<w>showbuffer</w>
|
<w>showbuffer</w>
|
||||||
<w>showpoints</w>
|
<w>showpoints</w>
|
||||||
<w>showstats</w>
|
<w>showstats</w>
|
||||||
@ -2753,11 +2756,13 @@
|
|||||||
<w>splitnumstr</w>
|
<w>splitnumstr</w>
|
||||||
<w>spwd</w>
|
<w>spwd</w>
|
||||||
<w>squadcore</w>
|
<w>squadcore</w>
|
||||||
|
<w>src's</w>
|
||||||
<w>srcabs</w>
|
<w>srcabs</w>
|
||||||
<w>srcattr</w>
|
<w>srcattr</w>
|
||||||
<w>srcdata</w>
|
<w>srcdata</w>
|
||||||
<w>srcdir</w>
|
<w>srcdir</w>
|
||||||
<w>srcfolder</w>
|
<w>srcfolder</w>
|
||||||
|
<w>srcfs</w>
|
||||||
<w>srcgrp</w>
|
<w>srcgrp</w>
|
||||||
<w>srcid</w>
|
<w>srcid</w>
|
||||||
<w>srcjson</w>
|
<w>srcjson</w>
|
||||||
@ -2840,6 +2845,7 @@
|
|||||||
<w>subdep</w>
|
<w>subdep</w>
|
||||||
<w>subdeps</w>
|
<w>subdeps</w>
|
||||||
<w>subdirs</w>
|
<w>subdirs</w>
|
||||||
|
<w>subdst</w>
|
||||||
<w>subfieldpath</w>
|
<w>subfieldpath</w>
|
||||||
<w>subfolders</w>
|
<w>subfolders</w>
|
||||||
<w>submpath</w>
|
<w>submpath</w>
|
||||||
@ -2852,6 +2858,7 @@
|
|||||||
<w>subprocesses</w>
|
<w>subprocesses</w>
|
||||||
<w>subrepos</w>
|
<w>subrepos</w>
|
||||||
<w>subsel</w>
|
<w>subsel</w>
|
||||||
|
<w>subsrc</w>
|
||||||
<w>subsys</w>
|
<w>subsys</w>
|
||||||
<w>subtypestr</w>
|
<w>subtypestr</w>
|
||||||
<w>subval</w>
|
<w>subval</w>
|
||||||
|
|||||||
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,4 +1,12 @@
|
|||||||
### 1.7.28 (build 21289, api 8, 2023-08-31)
|
### 1.7.28 (build 21293, api 8, 2023-08-31)
|
||||||
|
|
||||||
|
- Added some high level functionality for copying and deleting feature-sets to
|
||||||
|
the `tools/spinoff` tool. For example, to create your own `poo` feature-set,
|
||||||
|
do `tools/spinoff fset-copy template_fs poo`. Then do `make update` and `make
|
||||||
|
cmake` to build and run the app, and from within it you should be able to do
|
||||||
|
`import bapoo` to get at your nice shiny poo feature-set. When you are done
|
||||||
|
playing, you can do `tools/spinoff fset-delete poo` to blow away any traces of
|
||||||
|
it.
|
||||||
|
|
||||||
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
||||||
|
|
||||||
|
|||||||
6
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
6
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
@ -512,6 +512,7 @@
|
|||||||
<w>dstdir</w>
|
<w>dstdir</w>
|
||||||
<w>dstdirfull</w>
|
<w>dstdirfull</w>
|
||||||
<w>dstent</w>
|
<w>dstent</w>
|
||||||
|
<w>dstfs</w>
|
||||||
<w>dstnode</w>
|
<w>dstnode</w>
|
||||||
<w>dstpath</w>
|
<w>dstpath</w>
|
||||||
<w>dstr</w>
|
<w>dstr</w>
|
||||||
@ -662,6 +663,7 @@
|
|||||||
<w>flopsy</w>
|
<w>flopsy</w>
|
||||||
<w>flushhhhh</w>
|
<w>flushhhhh</w>
|
||||||
<w>fname</w>
|
<w>fname</w>
|
||||||
|
<w>fnamefilt</w>
|
||||||
<w>fnode</w>
|
<w>fnode</w>
|
||||||
<w>fnsu</w>
|
<w>fnsu</w>
|
||||||
<w>fnumc</w>
|
<w>fnumc</w>
|
||||||
@ -1619,9 +1621,11 @@
|
|||||||
<w>spinups</w>
|
<w>spinups</w>
|
||||||
<w>spivak</w>
|
<w>spivak</w>
|
||||||
<w>spwd</w>
|
<w>spwd</w>
|
||||||
|
<w>src's</w>
|
||||||
<w>srcabs</w>
|
<w>srcabs</w>
|
||||||
<w>srcattr</w>
|
<w>srcattr</w>
|
||||||
<w>srcfolder</w>
|
<w>srcfolder</w>
|
||||||
|
<w>srcfs</w>
|
||||||
<w>srcgrp</w>
|
<w>srcgrp</w>
|
||||||
<w>srcid</w>
|
<w>srcid</w>
|
||||||
<w>srcname</w>
|
<w>srcname</w>
|
||||||
@ -1683,6 +1687,7 @@
|
|||||||
<w>subargs</w>
|
<w>subargs</w>
|
||||||
<w>subc</w>
|
<w>subc</w>
|
||||||
<w>subclsssing</w>
|
<w>subclsssing</w>
|
||||||
|
<w>subdst</w>
|
||||||
<w>subentities</w>
|
<w>subentities</w>
|
||||||
<w>subfieldpath</w>
|
<w>subfieldpath</w>
|
||||||
<w>subitems</w>
|
<w>subitems</w>
|
||||||
@ -1691,6 +1696,7 @@
|
|||||||
<w>subplatform</w>
|
<w>subplatform</w>
|
||||||
<w>subscale</w>
|
<w>subscale</w>
|
||||||
<w>subscr</w>
|
<w>subscr</w>
|
||||||
|
<w>subsrc</w>
|
||||||
<w>subsys</w>
|
<w>subsys</w>
|
||||||
<w>subtypestr</w>
|
<w>subtypestr</w>
|
||||||
<w>successmsg</w>
|
<w>successmsg</w>
|
||||||
|
|||||||
@ -109,6 +109,7 @@ from babase._apputils import (
|
|||||||
is_browser_likely_available,
|
is_browser_likely_available,
|
||||||
garbage_collect,
|
garbage_collect,
|
||||||
get_remote_app_name,
|
get_remote_app_name,
|
||||||
|
AppHealthMonitor,
|
||||||
)
|
)
|
||||||
from babase._cloud import CloudSubsystem
|
from babase._cloud import CloudSubsystem
|
||||||
from babase._emptyappmode import EmptyAppMode
|
from babase._emptyappmode import EmptyAppMode
|
||||||
@ -176,6 +177,7 @@ __all__ = [
|
|||||||
'app',
|
'app',
|
||||||
'App',
|
'App',
|
||||||
'AppConfig',
|
'AppConfig',
|
||||||
|
'AppHealthMonitor',
|
||||||
'AppIntent',
|
'AppIntent',
|
||||||
'AppIntentDefault',
|
'AppIntentDefault',
|
||||||
'AppIntentExec',
|
'AppIntentExec',
|
||||||
|
|||||||
@ -13,6 +13,7 @@ from concurrent.futures import ThreadPoolExecutor
|
|||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
|
|
||||||
from efro.call import tpartial
|
from efro.call import tpartial
|
||||||
|
|
||||||
import _babase
|
import _babase
|
||||||
from babase._language import LanguageSubsystem
|
from babase._language import LanguageSubsystem
|
||||||
from babase._plugin import PluginSubsystem
|
from babase._plugin import PluginSubsystem
|
||||||
|
|||||||
@ -85,7 +85,9 @@ class MasterServerV1CallThread(threading.Thread):
|
|||||||
|
|
||||||
# Tearing the app down while this is running can lead to
|
# Tearing the app down while this is running can lead to
|
||||||
# rare crashes in LibSSL, so avoid that if at all possible.
|
# rare crashes in LibSSL, so avoid that if at all possible.
|
||||||
babase.shutdown_suppress_begin()
|
if not babase.shutdown_suppress_begin():
|
||||||
|
# App is already shutting down, so we're a no-op.
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
classic = babase.app.classic
|
classic = babase.app.classic
|
||||||
|
|||||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
# Build number and version of the ballistica binary we expect to be
|
# Build number and version of the ballistica binary we expect to be
|
||||||
# using.
|
# using.
|
||||||
TARGET_BALLISTICA_BUILD = 21289
|
TARGET_BALLISTICA_BUILD = 21293
|
||||||
TARGET_BALLISTICA_VERSION = '1.7.28'
|
TARGET_BALLISTICA_VERSION = '1.7.28'
|
||||||
|
|
||||||
|
|
||||||
@ -461,11 +461,12 @@ def _modular_main() -> None:
|
|||||||
# First baenv sets up things like Python paths the way the engine
|
# First baenv sets up things like Python paths the way the engine
|
||||||
# needs them, and then we import and run the engine.
|
# needs them, and then we import and run the engine.
|
||||||
#
|
#
|
||||||
# Below we're doing a slightly fancier version of that. Namely we do
|
# Below we're doing a slightly fancier version of that. Namely, we
|
||||||
# some processing of command line args to allow overriding of paths
|
# do some processing of command line args to allow overriding of
|
||||||
# or running explicit commands or whatever else. Our goal is that
|
# paths or running explicit commands or whatever else. Our goal is
|
||||||
# this modular form of the app should be basically indistinguishable
|
# that this modular form of the app should be basically
|
||||||
# from the monolithic form when used from the command line.
|
# indistinguishable from the monolithic form when used from the
|
||||||
|
# command line.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Take note that we're running via modular-main. The native
|
# Take note that we're running via modular-main. The native
|
||||||
|
|||||||
@ -4,8 +4,12 @@
|
|||||||
|
|
||||||
# ba_meta require api 8
|
# ba_meta require api 8
|
||||||
|
|
||||||
|
# Package up various private bits (including stuff from our native
|
||||||
|
# module) into a nice clean public API.
|
||||||
|
from _batemplatefs import hello_again_world
|
||||||
from batemplatefs._subsystem import TemplateFsSubsystem
|
from batemplatefs._subsystem import TemplateFsSubsystem
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'TemplateFsSubsystem',
|
'TemplateFsSubsystem',
|
||||||
|
'hello_again_world',
|
||||||
]
|
]
|
||||||
|
|||||||
@ -715,11 +715,33 @@ void BaseFeatureSet::DoPushObjCall(const PythonObjectSetBase* objset, int id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto BaseFeatureSet::IsAppStarted() const -> bool { return app_started_; }
|
auto BaseFeatureSet::IsAppStarted() const -> bool { return app_started_; }
|
||||||
void BaseFeatureSet::ShutdownSuppressBegin() { shutdown_suppress_count_++; }
|
|
||||||
|
auto BaseFeatureSet::ShutdownSuppressBegin() -> bool {
|
||||||
|
std::scoped_lock lock(shutdown_suppress_lock_);
|
||||||
|
if (!shutdown_suppress_disallowed_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
shutdown_suppress_count_++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void BaseFeatureSet::ShutdownSuppressEnd() {
|
void BaseFeatureSet::ShutdownSuppressEnd() {
|
||||||
|
std::scoped_lock lock(shutdown_suppress_lock_);
|
||||||
shutdown_suppress_count_--;
|
shutdown_suppress_count_--;
|
||||||
assert(shutdown_suppress_count_ >= 0);
|
assert(shutdown_suppress_count_ >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto BaseFeatureSet::ShutdownSuppressGetCount() -> int {
|
||||||
|
std::scoped_lock lock(shutdown_suppress_lock_);
|
||||||
|
return shutdown_suppress_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseFeatureSet::ShutdownSuppressDisallow() {
|
||||||
|
std::scoped_lock lock(shutdown_suppress_lock_);
|
||||||
|
assert(!shutdown_suppress_disallowed_);
|
||||||
|
shutdown_suppress_disallowed_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
auto BaseFeatureSet::GetReturnValue() const -> int { return return_value(); }
|
auto BaseFeatureSet::GetReturnValue() const -> int { return return_value(); }
|
||||||
|
|
||||||
} // namespace ballistica::base
|
} // namespace ballistica::base
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#ifndef BALLISTICA_BASE_BASE_H_
|
#ifndef BALLISTICA_BASE_BASE_H_
|
||||||
#define BALLISTICA_BASE_BASE_H_
|
#define BALLISTICA_BASE_BASE_H_
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -690,9 +691,18 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
void DoPushObjCall(const PythonObjectSetBase* objset, int id,
|
void DoPushObjCall(const PythonObjectSetBase* objset, int id,
|
||||||
const std::string& arg) override;
|
const std::string& arg) override;
|
||||||
void OnReachedEndOfBaBaseImport();
|
void OnReachedEndOfBaBaseImport();
|
||||||
void ShutdownSuppressBegin();
|
|
||||||
|
/// Begin a shutdown-suppressing operation. Returns true if the operation
|
||||||
|
/// can proceed; otherwise shutdown has already begun and the operation
|
||||||
|
/// should be aborted.
|
||||||
|
auto ShutdownSuppressBegin() -> bool;
|
||||||
|
|
||||||
|
/// End a shutddown-suppressing operation. Should only be called after a
|
||||||
|
/// successful begin.
|
||||||
void ShutdownSuppressEnd();
|
void ShutdownSuppressEnd();
|
||||||
auto shutdown_suppress_count() const { return shutdown_suppress_count_; }
|
|
||||||
|
auto ShutdownSuppressGetCount() -> int;
|
||||||
|
void ShutdownSuppressDisallow();
|
||||||
|
|
||||||
/// Called in the logic thread once our screen is up and assets are
|
/// Called in the logic thread once our screen is up and assets are
|
||||||
/// loading.
|
/// loading.
|
||||||
@ -756,6 +766,8 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
|||||||
StressTest* stress_test_;
|
StressTest* stress_test_;
|
||||||
|
|
||||||
std::string console_startup_messages_;
|
std::string console_startup_messages_;
|
||||||
|
std::mutex shutdown_suppress_lock_;
|
||||||
|
bool shutdown_suppress_disallowed_;
|
||||||
int shutdown_suppress_count_{};
|
int shutdown_suppress_count_{};
|
||||||
bool tried_importing_plus_{};
|
bool tried_importing_plus_{};
|
||||||
bool tried_importing_classic_{};
|
bool tried_importing_classic_{};
|
||||||
|
|||||||
@ -226,7 +226,10 @@ void Logic::OnAppShutdown() {
|
|||||||
// Nuke the app from orbit if we get stuck while shutting down.
|
// Nuke the app from orbit if we get stuck while shutting down.
|
||||||
g_core->StartSuicideTimer("shutdown", 10000);
|
g_core->StartSuicideTimer("shutdown", 10000);
|
||||||
|
|
||||||
// Let our subsystems know we're shutting down.
|
// Tell base to disallow shutdown-suppressors from here on out.
|
||||||
|
g_base->ShutdownSuppressDisallow();
|
||||||
|
|
||||||
|
// Let our logic thread subsystems know we're shutting down.
|
||||||
// Note: Keep these in opposite order of OnAppStart.
|
// Note: Keep these in opposite order of OnAppStart.
|
||||||
// Note2: Any shutdown processes that take a non-zero amount of time
|
// Note2: Any shutdown processes that take a non-zero amount of time
|
||||||
// should be registered as shutdown-tasks
|
// should be registered as shutdown-tasks
|
||||||
|
|||||||
@ -1495,8 +1495,12 @@ static PyMethodDef PyGetImmediateReturnCodeDef = {
|
|||||||
static auto PyShutdownSuppressBegin(PyObject* self) -> PyObject* {
|
static auto PyShutdownSuppressBegin(PyObject* self) -> PyObject* {
|
||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
assert(g_base);
|
assert(g_base);
|
||||||
g_base->ShutdownSuppressBegin();
|
auto val = g_base->ShutdownSuppressBegin();
|
||||||
Py_RETURN_NONE;
|
if (val) {
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
} else {
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1505,7 +1509,7 @@ static PyMethodDef PyShutdownSuppressBeginDef = {
|
|||||||
(PyCFunction)PyShutdownSuppressBegin, // method
|
(PyCFunction)PyShutdownSuppressBegin, // method
|
||||||
METH_NOARGS, // flags
|
METH_NOARGS, // flags
|
||||||
|
|
||||||
"shutdown_suppress_begin() -> None\n"
|
"shutdown_suppress_begin() -> bool\n"
|
||||||
"\n"
|
"\n"
|
||||||
"(internal)\n",
|
"(internal)\n",
|
||||||
};
|
};
|
||||||
@ -1536,7 +1540,7 @@ static PyMethodDef PyShutdownSuppressEndDef = {
|
|||||||
static auto PyShutdownSuppressCount(PyObject* self) -> PyObject* {
|
static auto PyShutdownSuppressCount(PyObject* self) -> PyObject* {
|
||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
assert(g_base);
|
assert(g_base);
|
||||||
return PyLong_FromLong(g_base->shutdown_suppress_count());
|
return PyLong_FromLong(g_base->ShutdownSuppressGetCount());
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,9 +15,8 @@ CoreFeatureSet* g_core{};
|
|||||||
BaseSoftInterface* g_base_soft{};
|
BaseSoftInterface* g_base_soft{};
|
||||||
|
|
||||||
auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
|
auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
|
||||||
// In monolithic builds we can accept an explicit core-config the first
|
// In monolithic builds, we accept an explicit core-config the first time
|
||||||
// time we're imported. In this case, Python is not even spun up yet so
|
// we're imported. It is fully up to the caller to build the config.
|
||||||
// it can influence even that.
|
|
||||||
if (g_buildconfig.monolithic_build()) {
|
if (g_buildconfig.monolithic_build()) {
|
||||||
if (config != nullptr) {
|
if (config != nullptr) {
|
||||||
if (g_core != nullptr) {
|
if (g_core != nullptr) {
|
||||||
@ -29,17 +28,17 @@ auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
|
|||||||
DoImport(*config);
|
DoImport(*config);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No config passed; use a default.
|
// If no config is passed, use a default. If the user wants env vars
|
||||||
|
// or anything else factored in, they should do so themselves in the
|
||||||
|
// config they pass (CoreConfig::ForEnvVars(), etc.).
|
||||||
if (g_core == nullptr) {
|
if (g_core == nullptr) {
|
||||||
DoImport({});
|
DoImport({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// In modular builds we autogenerate a CoreConfig that takes into
|
// In modular builds, we generate a CoreConfig *after* Python is spun
|
||||||
// account only env-vars (or env-vars plus Python args if we're being
|
// up, implicitly using Python's sys args and/or env vars when
|
||||||
// run via the baenv script). In this case, Python is already spun up
|
// applicable.
|
||||||
// and baenv already handled any Python environment stuff so we have
|
|
||||||
// less to do.
|
|
||||||
if (config != nullptr) {
|
if (config != nullptr) {
|
||||||
FatalError("CoreConfig can't be explicitly passed in modular builds.");
|
FatalError("CoreConfig can't be explicitly passed in modular builds.");
|
||||||
}
|
}
|
||||||
@ -57,6 +56,7 @@ auto CoreFeatureSet::Import(const CoreConfig* config) -> CoreFeatureSet* {
|
|||||||
DoImport(CoreConfig::ForArgsAndEnvVars(static_cast<int>(argv.size()),
|
DoImport(CoreConfig::ForArgsAndEnvVars(static_cast<int>(argv.size()),
|
||||||
argv.data()));
|
argv.data()));
|
||||||
} else {
|
} else {
|
||||||
|
// Not using Python sys args but we still want to process env vars.
|
||||||
DoImport(CoreConfig::ForEnvVars());
|
DoImport(CoreConfig::ForEnvVars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,27 +24,26 @@ class CoreFeatureSet;
|
|||||||
class BaseSoftInterface;
|
class BaseSoftInterface;
|
||||||
|
|
||||||
// Our feature-set's globals.
|
// Our feature-set's globals.
|
||||||
// Feature-sets should NEVER directly access globals in another feature-set's
|
//
|
||||||
// namespace. All functionality we need from other feature-sets should be
|
// Feature-sets should NEVER directly access globals in another
|
||||||
// imported into globals in our own namespace. Generally we do this when we
|
// feature-set's namespace. All functionality we need from other
|
||||||
// are initially imported (just as regular Python modules do).
|
// feature-sets should be imported into globals in our own namespace.
|
||||||
|
// Generally we do this when we are initially imported (just as regular
|
||||||
|
// Python modules do).
|
||||||
|
|
||||||
|
// Our pointer to our own feature-set.
|
||||||
extern CoreFeatureSet* g_core;
|
extern CoreFeatureSet* g_core;
|
||||||
|
|
||||||
// We don't require the base feature-set but can use it if present.
|
// We don't require the base feature-set but can use it if present. Base
|
||||||
// Base will supply us with this pointer if/when it spins up.
|
// will supply us with this pointer if/when it spins up. So we must never
|
||||||
// So we must never assume this pointer is valid and must check for it
|
// assume this pointer is valid and must check for it with each use.
|
||||||
// with each use.
|
|
||||||
extern BaseSoftInterface* g_base_soft;
|
extern BaseSoftInterface* g_base_soft;
|
||||||
|
|
||||||
/// Platform-agnostic global state for our overall system.
|
/// Core engine functionality.
|
||||||
/// This gets created whenever we are used in any capacity, even if
|
|
||||||
/// we don't create/run an app.
|
|
||||||
/// Ideally most things here should be migrated to more specific
|
|
||||||
/// subsystems.
|
|
||||||
class CoreFeatureSet {
|
class CoreFeatureSet {
|
||||||
public:
|
public:
|
||||||
/// Import the core feature set. A core-config can be passed ONLY
|
/// Import the core feature set. A core-config can be passed ONLY in
|
||||||
/// in monolithic builds when it is guaranteed that the Import will be
|
/// monolithic builds when it is guaranteed that the Import will be
|
||||||
/// allocating the CoreFeatureSet singleton.
|
/// allocating the CoreFeatureSet singleton.
|
||||||
static auto Import(const CoreConfig* config = nullptr) -> CoreFeatureSet*;
|
static auto Import(const CoreConfig* config = nullptr) -> CoreFeatureSet*;
|
||||||
|
|
||||||
@ -76,32 +75,35 @@ class CoreFeatureSet {
|
|||||||
auto HeadlessMode() -> bool;
|
auto HeadlessMode() -> bool;
|
||||||
|
|
||||||
/// Return current app-time in milliseconds.
|
/// Return current app-time in milliseconds.
|
||||||
|
///
|
||||||
/// App-time is basically the total time that the engine has been actively
|
/// App-time is basically the total time that the engine has been actively
|
||||||
/// running. (The 'App' here is a slight misnomer). It will stop progressing
|
/// running. (The 'App' here is a slight misnomer). It will stop
|
||||||
/// while the app is suspended and will never go backwards.
|
/// progressing while the app is suspended and will never go backwards.
|
||||||
auto GetAppTimeMillisecs() -> millisecs_t;
|
auto GetAppTimeMillisecs() -> millisecs_t;
|
||||||
|
|
||||||
/// Return current app-time in microseconds.
|
/// Return current app-time in microseconds.
|
||||||
|
///
|
||||||
/// App-time is basically the total time that the engine has been actively
|
/// App-time is basically the total time that the engine has been actively
|
||||||
/// running. (The 'App' here is a slight misnomer). It will stop progressing
|
/// running. (The 'App' here is a slight misnomer). It will stop
|
||||||
/// while the app is suspended and will never go backwards.
|
/// progressing while the app is suspended and will never go backwards.
|
||||||
auto GetAppTimeMicrosecs() -> microsecs_t;
|
auto GetAppTimeMicrosecs() -> microsecs_t;
|
||||||
|
|
||||||
/// Return current app-time in seconds.
|
/// Return current app-time in seconds.
|
||||||
|
///
|
||||||
/// App-time is basically the total time that the engine has been actively
|
/// App-time is basically the total time that the engine has been actively
|
||||||
/// running. (The 'App' here is a slight misnomer). It will stop progressing
|
/// running. (The 'App' here is a slight misnomer). It will stop
|
||||||
/// while the app is suspended and will never go backwards.
|
/// progressing while the app is suspended and will never go backwards.
|
||||||
auto GetAppTimeSeconds() -> double;
|
auto GetAppTimeSeconds() -> double;
|
||||||
|
|
||||||
/// Are we in the thread the main event loop is running on?
|
/// Are we in the thread the main event loop is running on? Generally this
|
||||||
/// Generally this is the thread that runs graphics and os event processing.
|
/// is the thread that runs graphics and os event processing.
|
||||||
auto InMainThread() -> bool;
|
auto InMainThread() -> bool;
|
||||||
|
|
||||||
/// Log a boot-related message (only if core_config.lifecycle_log is true).
|
/// Log a boot-related message (only if core_config.lifecycle_log is true).
|
||||||
void LifecycleLog(const char* msg, double offset_seconds = 0.0);
|
void LifecycleLog(const char* msg, double offset_seconds = 0.0);
|
||||||
|
|
||||||
/// Base path of build src dir so we can attempt to remove it from
|
/// Base path of build src dir so we can attempt to remove it from any
|
||||||
/// any source file paths we print.
|
/// source file paths we print.
|
||||||
auto build_src_dir() const { return build_src_dir_; }
|
auto build_src_dir() const { return build_src_dir_; }
|
||||||
|
|
||||||
const auto& legacy_user_agent_string() const {
|
const auto& legacy_user_agent_string() const {
|
||||||
@ -113,8 +115,8 @@ class CoreFeatureSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if baenv values have been locked in: python paths, log
|
/// Return true if baenv values have been locked in: python paths, log
|
||||||
/// handling, etc. Early-running code may wish to explicitly avoid making log
|
/// handling, etc. Early-running code may wish to explicitly avoid making
|
||||||
/// calls until this condition is met to ensure predictable behavior.
|
/// log calls until this condition is met to ensure predictable behavior.
|
||||||
auto have_ba_env_vals() const { return have_ba_env_vals_; }
|
auto have_ba_env_vals() const { return have_ba_env_vals_; }
|
||||||
|
|
||||||
/// Return the directory where the app expects to find its bundled Python
|
/// Return the directory where the app expects to find its bundled Python
|
||||||
@ -138,8 +140,8 @@ class CoreFeatureSet {
|
|||||||
/// Return the directory where bundled 3rd party Python files live.
|
/// Return the directory where bundled 3rd party Python files live.
|
||||||
auto GetSitePythonDirectory() -> std::optional<std::string>;
|
auto GetSitePythonDirectory() -> std::optional<std::string>;
|
||||||
|
|
||||||
// Are we using a non-standard app python dir (such as a 'sys' dir within a
|
// Are we using a non-standard app python dir (such as a 'sys' dir within
|
||||||
// user-python-dir).
|
// a user-python-dir).
|
||||||
auto using_custom_app_python_dir() const {
|
auto using_custom_app_python_dir() const {
|
||||||
return using_custom_app_python_dir_;
|
return using_custom_app_python_dir_;
|
||||||
}
|
}
|
||||||
@ -165,7 +167,6 @@ class CoreFeatureSet {
|
|||||||
bool reset_vr_orientation{};
|
bool reset_vr_orientation{};
|
||||||
bool user_ran_commands{};
|
bool user_ran_commands{};
|
||||||
std::thread::id main_thread_id{};
|
std::thread::id main_thread_id{};
|
||||||
|
|
||||||
bool vr_mode;
|
bool vr_mode;
|
||||||
std::mutex thread_name_map_mutex;
|
std::mutex thread_name_map_mutex;
|
||||||
std::unordered_map<std::thread::id, std::string> thread_name_map;
|
std::unordered_map<std::thread::id, std::string> thread_name_map;
|
||||||
@ -177,11 +178,11 @@ class CoreFeatureSet {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit CoreFeatureSet(CoreConfig config);
|
||||||
|
static void DoImport(const CoreConfig& config);
|
||||||
static auto CalcBuildSrcDir() -> std::string;
|
static auto CalcBuildSrcDir() -> std::string;
|
||||||
void RunSanityChecks();
|
void RunSanityChecks();
|
||||||
static void DoImport(const CoreConfig& config);
|
|
||||||
void UpdateAppTime();
|
void UpdateAppTime();
|
||||||
explicit CoreFeatureSet(CoreConfig config);
|
|
||||||
void PostInit();
|
void PostInit();
|
||||||
bool tried_importing_base_{};
|
bool tried_importing_base_{};
|
||||||
EventLoop* main_event_loop_{};
|
EventLoop* main_event_loop_{};
|
||||||
|
|||||||
@ -27,8 +27,9 @@
|
|||||||
|
|
||||||
// ------------------------- PLATFORM SELECTION --------------------------------
|
// ------------------------- PLATFORM SELECTION --------------------------------
|
||||||
|
|
||||||
// This ugly chunk of macros simply pulls in the correct platform class header
|
// This ugly chunk of macros simply pulls in the correct platform class
|
||||||
// for each platform and defines the actual class g_core->platform will be.
|
// header for each platform and defines the actual class g_core->platform
|
||||||
|
// will be.
|
||||||
|
|
||||||
// Android ---------------------------------------------------------------------
|
// Android ---------------------------------------------------------------------
|
||||||
|
|
||||||
@ -85,6 +86,7 @@
|
|||||||
|
|
||||||
// A call that can be used by custom built native libraries (Python, etc.)
|
// A call that can be used by custom built native libraries (Python, etc.)
|
||||||
// to forward along debug messages to us.
|
// to forward along debug messages to us.
|
||||||
|
//
|
||||||
// FIXME: Reconcile this with our existing C++ version. This one does not
|
// FIXME: Reconcile this with our existing C++ version. This one does not
|
||||||
// require the engine to be spun up so it better suited for things like
|
// require the engine to be spun up so it better suited for things like
|
||||||
// debugging native libs.
|
// debugging native libs.
|
||||||
|
|||||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
|||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|
||||||
// These are set automatically via script; don't modify them here.
|
// These are set automatically via script; don't modify them here.
|
||||||
const int kEngineBuildNumber = 21289;
|
const int kEngineBuildNumber = 21293;
|
||||||
const char* kEngineVersion = "1.7.28";
|
const char* kEngineVersion = "1.7.28";
|
||||||
const int kEngineApiVersion = 8;
|
const int kEngineApiVersion = 8;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Template Feature Set
|
# Template Fs Feature Set
|
||||||
|
|
||||||
This is an empty feature-set for use as reference or as a starting point when
|
This is an empty feature-set for use as reference or as a starting point when
|
||||||
implementing new ones.
|
implementing new ones.
|
||||||
|
|||||||
@ -9,16 +9,18 @@
|
|||||||
|
|
||||||
namespace ballistica::template_fs {
|
namespace ballistica::template_fs {
|
||||||
|
|
||||||
// Declare a plain c PyInit_XXX function for our Python module;
|
// Declare a plain C PyInit_XXX function for our Python module. This is how
|
||||||
// this is how Python inits our binary module (and by extension, our
|
// Python inits our binary module (and by extension, our entire
|
||||||
// entire feature-set).
|
// feature-set).
|
||||||
extern "C" auto PyInit__batemplatefs() -> PyObject* {
|
extern "C" auto PyInit__batemplatefs() -> PyObject* {
|
||||||
auto* builder = new PythonModuleBuilder(
|
auto* builder = new PythonModuleBuilder(
|
||||||
"_batemplatefs",
|
"_batemplatefs",
|
||||||
// Native methods to add.
|
|
||||||
|
// Our native methods.
|
||||||
{PythonMethodsTemplateFs::GetMethods()},
|
{PythonMethodsTemplateFs::GetMethods()},
|
||||||
// Our module exec. Here we can add classes, import other modules,
|
|
||||||
// or whatever else (same as a regular Python script module).
|
// Our module exec. Here we can add classes, import other modules, or
|
||||||
|
// whatever else (same as a regular Python script module).
|
||||||
[](PyObject* module) -> int {
|
[](PyObject* module) -> int {
|
||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
TemplateFsFeatureSet::OnModuleExec(module);
|
TemplateFsFeatureSet::OnModuleExec(module);
|
||||||
@ -38,14 +40,16 @@ void TemplateFsPython::ImportPythonObjs() {
|
|||||||
|
|
||||||
void TemplateFsPython::HelloWorld() {
|
void TemplateFsPython::HelloWorld() {
|
||||||
// Hold the GIL throughout this call so we can run in any thread.
|
// Hold the GIL throughout this call so we can run in any thread.
|
||||||
// Alternately we could limit this function to the logic thread
|
// Alternately, we could limit this function to the logic thread which
|
||||||
// which always holds the GIL. In that case we'd want to
|
// always holds the GIL. In that case we'd want to stick a
|
||||||
// stick a BA_PRECONDITION(InLogicThread()) here to be sure.
|
// BA_PRECONDITION(InLogicThread()) here to so we'd raise an Exception if
|
||||||
|
// someone called us from another thread.
|
||||||
auto gil{Python::ScopedInterpreterLock()};
|
auto gil{Python::ScopedInterpreterLock()};
|
||||||
|
|
||||||
// Run the Python callable we grabbed. This will simply print any
|
// Run the Python callable we grabbed in our binding code. By default,
|
||||||
// errors, but we could disable that print and look at the call
|
// this Call() will simply print any errors, but we could disable that
|
||||||
// results if any logic depended on this code running successfully.
|
// print and look at the call results if any logic depended on this code
|
||||||
|
// running successfully.
|
||||||
objs_.Get(ObjID::kHelloWorldCall).Call();
|
objs_.Get(ObjID::kHelloWorldCall).Call();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,13 +9,17 @@ import sys
|
|||||||
import subprocess
|
import subprocess
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import assert_never
|
from typing import assert_never, TYPE_CHECKING
|
||||||
|
|
||||||
from efro.error import CleanError
|
from efro.error import CleanError
|
||||||
from efro.terminal import Clr
|
from efro.terminal import Clr
|
||||||
from efrotools import replace_exact
|
from efrotools import replace_exact
|
||||||
|
|
||||||
from batools.spinoff._context import SpinoffContext
|
from batools.spinoff._context import SpinoffContext
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from batools.featureset import FeatureSet
|
||||||
|
|
||||||
|
|
||||||
class Command(Enum):
|
class Command(Enum):
|
||||||
"""Our top level commands."""
|
"""Our top level commands."""
|
||||||
@ -32,6 +36,8 @@ class Command(Enum):
|
|||||||
FEATURESETS = 'featuresets'
|
FEATURESETS = 'featuresets'
|
||||||
CREATE = 'create'
|
CREATE = 'create'
|
||||||
ADD_SUBMODULE_PARENT = 'add-submodule-parent'
|
ADD_SUBMODULE_PARENT = 'add-submodule-parent'
|
||||||
|
FEATURE_SET_COPY = 'fset-copy'
|
||||||
|
FEATURE_SET_DELETE = 'fset-delete'
|
||||||
|
|
||||||
|
|
||||||
def spinoff_main() -> None:
|
def spinoff_main() -> None:
|
||||||
@ -101,6 +107,10 @@ def _main() -> None:
|
|||||||
|
|
||||||
public = getprojectconfig(Path(dst_root))['public']
|
public = getprojectconfig(Path(dst_root))['public']
|
||||||
_do_add_submodule_parent(dst_root, is_new=False, public=public)
|
_do_add_submodule_parent(dst_root, is_new=False, public=public)
|
||||||
|
elif cmd is Command.FEATURE_SET_COPY:
|
||||||
|
_do_featureset_copy()
|
||||||
|
elif cmd is Command.FEATURE_SET_DELETE:
|
||||||
|
_do_featureset_delete()
|
||||||
else:
|
else:
|
||||||
assert_never(cmd)
|
assert_never(cmd)
|
||||||
|
|
||||||
@ -250,6 +260,251 @@ def _do_featuresets(dst_root: str) -> None:
|
|||||||
print(f' {Clr.BLU}{fset.name}{Clr.RST}')
|
print(f' {Clr.BLU}{fset.name}{Clr.RST}')
|
||||||
|
|
||||||
|
|
||||||
|
def _fset_paths() -> list[str]:
|
||||||
|
"""Given a feature-set, return all paths associated with it."""
|
||||||
|
return [
|
||||||
|
'config/featuresets/featureset_$(NAME).py',
|
||||||
|
'src/assets/ba_data/python/$(NAME_PY_PKG)',
|
||||||
|
'src/ballistica/$(NAME)',
|
||||||
|
'src/meta/$(NAME_PY_PKG_META)',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _filter_fset_path(path: str, fset: FeatureSet) -> str:
|
||||||
|
return (
|
||||||
|
path.replace('$(NAME)', fset.name)
|
||||||
|
.replace('$(NAME_PY_PKG)', fset.name_python_package)
|
||||||
|
.replace('$(NAME_PY_PKG_META)', fset.name_python_package_meta)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _do_featureset_delete() -> None:
|
||||||
|
from batools.featureset import FeatureSet
|
||||||
|
|
||||||
|
args = sys.argv[2:]
|
||||||
|
if len(args) != 1:
|
||||||
|
raise CleanError('Expected a featureset name.')
|
||||||
|
|
||||||
|
name = args[0]
|
||||||
|
|
||||||
|
# Just make a theoretical new featureset in case only parts of it
|
||||||
|
# exist. (custom name formatting shouldnt matter here anyway)
|
||||||
|
fset = FeatureSet(name)
|
||||||
|
|
||||||
|
if not os.path.exists('config/featuresets'):
|
||||||
|
raise CleanError('Cannot run from this directory.')
|
||||||
|
|
||||||
|
paths_to_delete: list[str] = []
|
||||||
|
for path in _fset_paths():
|
||||||
|
paths_to_delete.append(_filter_fset_path(path, fset))
|
||||||
|
|
||||||
|
print(
|
||||||
|
'\n' + '⎯' * 80 + f'\n{Clr.BLD}Deleting feature-set{Clr.RST}'
|
||||||
|
f' {Clr.SMAG}{Clr.BLD}{name}{Clr.RST}{Clr.BLD}...{Clr.RST}\n'
|
||||||
|
+ '⎯' * 80
|
||||||
|
+ '\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
found_something = False
|
||||||
|
for path in paths_to_delete:
|
||||||
|
if os.path.exists(path):
|
||||||
|
found_something = True
|
||||||
|
print(f' Deleting {Clr.MAG}{path}{Clr.RST}')
|
||||||
|
subprocess.run(['rm', '-rf', path], check=True)
|
||||||
|
if not found_something:
|
||||||
|
print(
|
||||||
|
f' {Clr.WHT}No feature-set components found;'
|
||||||
|
f' nothing to be done.{Clr.RST}'
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"\n{Clr.GRN}{Clr.BLD}Job's done!{Clr.RST}\n"
|
||||||
|
f'{Clr.BLD}Next, run'
|
||||||
|
f' {Clr.BLU}`make update`{Clr.RST}{Clr.BLD} to update project'
|
||||||
|
f' files to reflect these changes.{Clr.RST}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _do_featureset_copy() -> None:
|
||||||
|
# pylint: disable=too-many-locals
|
||||||
|
from efrotools import extract_flag
|
||||||
|
|
||||||
|
from batools.featureset import FeatureSet
|
||||||
|
|
||||||
|
args = sys.argv[2:]
|
||||||
|
|
||||||
|
force = extract_flag(args, '--force')
|
||||||
|
|
||||||
|
if len(args) != 2:
|
||||||
|
raise CleanError('Expected a src and dst featureset name.')
|
||||||
|
|
||||||
|
src = args[0]
|
||||||
|
dst = args[1]
|
||||||
|
|
||||||
|
if not os.path.exists('config/featuresets'):
|
||||||
|
raise CleanError('Cannot run from this directory.')
|
||||||
|
|
||||||
|
# This will make sure both feature-set names are valid and give us
|
||||||
|
# name variations. Load src from the project to pick up custom title
|
||||||
|
# variations/etc.
|
||||||
|
fsets = {f.name: f for f in FeatureSet.get_all_for_project('.')}
|
||||||
|
if src not in fsets:
|
||||||
|
raise CleanError('src feature-set {src} not found.')
|
||||||
|
srcfs = fsets[src]
|
||||||
|
# Just go with defaults for dst. Note that this means any custom
|
||||||
|
# title forms in src's config script will get filtered to be setting
|
||||||
|
# the default form of dst, which is redundant. Maybe we could filter that
|
||||||
|
# out.
|
||||||
|
dstfs = FeatureSet(dst)
|
||||||
|
|
||||||
|
# Make sure src *does* exist.
|
||||||
|
if not os.path.exists(f'config/featuresets/featureset_{src}.py'):
|
||||||
|
raise CleanError(f"Src feature-set '{src}' not found.")
|
||||||
|
|
||||||
|
# Make sure dst does *not* exist (unless we're forcing).
|
||||||
|
if os.path.exists(f'config/featuresets/featureset_{dst}.py') and not force:
|
||||||
|
raise CleanError(
|
||||||
|
f"Dst feature-set '{dst}' already exists."
|
||||||
|
' Use --force to blow it away.'
|
||||||
|
)
|
||||||
|
|
||||||
|
paths_to_copy: list[tuple[str, str]] = []
|
||||||
|
for path in _fset_paths():
|
||||||
|
paths_to_copy.append(
|
||||||
|
(_filter_fset_path(path, srcfs), _filter_fset_path(path, dstfs))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Replace variations of our name. Note that we don't have to include
|
||||||
|
# stuff like name_python_package_meta here because that is covered
|
||||||
|
# by our base name replacement. Also note that we include upper()
|
||||||
|
# for C/C++ header #ifndefs.
|
||||||
|
subs = [
|
||||||
|
(srcfs.name, dstfs.name),
|
||||||
|
(srcfs.name_compact, dstfs.name_compact),
|
||||||
|
(srcfs.name_title, dstfs.name_title),
|
||||||
|
(srcfs.name_camel, dstfs.name_camel),
|
||||||
|
(srcfs.name.upper(), dstfs.name.upper()),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Sanity check: we don't currently support renaming subdirs, so error
|
||||||
|
# if that would happen.
|
||||||
|
for srcpath, _dstpath in paths_to_copy:
|
||||||
|
for root, dirs, _fnames in os.walk(srcpath):
|
||||||
|
for dname in dirs:
|
||||||
|
if any(sub[0] in dname for sub in subs):
|
||||||
|
raise CleanError(
|
||||||
|
'Directory name filtering is not supported'
|
||||||
|
f" (would filter '{root}/{dname}')."
|
||||||
|
)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# Ok, at this point we get started working and assume things will succeed.
|
||||||
|
# If anything fails at this point we should add a pre-check for it above.
|
||||||
|
print(
|
||||||
|
'\n' + '⎯' * 80 + f'\n{Clr.BLD}Copying feature-set{Clr.RST}'
|
||||||
|
f' {Clr.SMAG}{Clr.BLD}{src}{Clr.RST}'
|
||||||
|
f' {Clr.BLD}to{Clr.RST}'
|
||||||
|
f' {Clr.SMAG}{Clr.BLD}{dst}{Clr.RST}'
|
||||||
|
f'{Clr.BLD}...{Clr.RST}\n' + '⎯' * 80
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f'\n{Clr.BLD}Will filter the following text:{Clr.RST}')
|
||||||
|
for subsrc, subdst in subs:
|
||||||
|
print(
|
||||||
|
f' {Clr.MAG}{subsrc}{Clr.RST}'
|
||||||
|
f' {Clr.BLD}->{Clr.RST} {Clr.MAG}{subdst}{Clr.RST}'
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f'\n{Clr.BLD}Copying/filtering files...{Clr.RST}')
|
||||||
|
|
||||||
|
for srcpath, dstpath in paths_to_copy:
|
||||||
|
_do_featureset_copy_dir(srcpath, dstpath, subs, force)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"\n{Clr.GRN}{Clr.BLD}Job's done!{Clr.RST}\n"
|
||||||
|
f'{Clr.BLD}Next, run'
|
||||||
|
f' {Clr.BLU}`make update`{Clr.RST}{Clr.BLD} to update project'
|
||||||
|
f' files to reflect these changes.{Clr.RST}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _do_featureset_copy_dir(
|
||||||
|
srcpath: str, dstpath: str, subs: list[tuple[str, str]], force: bool
|
||||||
|
) -> None:
|
||||||
|
# pylint: disable=too-many-locals
|
||||||
|
# pylint: disable=too-many-branches
|
||||||
|
|
||||||
|
# This feature-set might not have this component. No biggie.
|
||||||
|
if not os.path.exists(srcpath):
|
||||||
|
return
|
||||||
|
|
||||||
|
if force:
|
||||||
|
subprocess.run(['rm', '-rf', dstpath], check=True)
|
||||||
|
|
||||||
|
if not os.path.exists(srcpath):
|
||||||
|
raise CleanError(f'src path {srcpath} is not a dir.')
|
||||||
|
if os.path.exists(dstpath):
|
||||||
|
raise CleanError(f'dst path {srcpath} already exists.')
|
||||||
|
|
||||||
|
filtered_exts = ['.cc', '.h', '.py', '.md', '.inc']
|
||||||
|
|
||||||
|
# Eww; reinventing the wheel here; should tap into existing
|
||||||
|
# spinoff logic or something.
|
||||||
|
cruft_names = ['.DS_Store', 'mgen', '_mgen']
|
||||||
|
|
||||||
|
# We currently just copy the full dir and then rename/filter
|
||||||
|
# individual files. If we need to filter subdir names at some point
|
||||||
|
# we'll need fancier code.
|
||||||
|
subprocess.run(['cp', '-r', srcpath, dstpath], check=True)
|
||||||
|
for root, dnames, fnames in os.walk(dstpath, topdown=True):
|
||||||
|
for dname in dnames:
|
||||||
|
if dname in cruft_names:
|
||||||
|
# Prevent us from recursing into it and blow it away.
|
||||||
|
dnames.remove(dname)
|
||||||
|
subprocess.run(
|
||||||
|
['rm', '-rf', os.path.join(root, dname)], check=True
|
||||||
|
)
|
||||||
|
for fname in fnames:
|
||||||
|
if fname in cruft_names:
|
||||||
|
os.unlink(os.path.join(root, fname))
|
||||||
|
continue
|
||||||
|
fnamefilt = fname
|
||||||
|
for subsrc, subdst in subs:
|
||||||
|
fnamefilt = fnamefilt.replace(subsrc, subdst)
|
||||||
|
if fnamefilt != fname:
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
'mv',
|
||||||
|
os.path.join(root, fname),
|
||||||
|
os.path.join(root, fnamefilt),
|
||||||
|
],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
# Now filter contents.
|
||||||
|
if not any(fname.endswith(ext) for ext in filtered_exts):
|
||||||
|
print(
|
||||||
|
f'{Clr.YLW}WARNING:'
|
||||||
|
f' not filtering file with unrecognized extension:'
|
||||||
|
f" '{fname}'{Clr.RST}"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
with open(
|
||||||
|
os.path.join(root, fnamefilt), encoding='utf-8'
|
||||||
|
) as infile:
|
||||||
|
contents = infile.read()
|
||||||
|
for subsrc, subdst in subs:
|
||||||
|
contents = contents.replace(subsrc, subdst)
|
||||||
|
with open(
|
||||||
|
os.path.join(root, fnamefilt), 'w', encoding='utf-8'
|
||||||
|
) as outfile:
|
||||||
|
outfile.write(contents)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f' {Clr.MAG}{srcpath}{Clr.RST} {Clr.BLD}->{Clr.RST}'
|
||||||
|
f' {Clr.MAG}{dstpath}{Clr.RST}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _do_override(src_root: str | None, dst_root: str) -> None:
|
def _do_override(src_root: str | None, dst_root: str) -> None:
|
||||||
if src_root is None:
|
if src_root is None:
|
||||||
raise CleanError('This only works on dst projects.')
|
raise CleanError('This only works on dst projects.')
|
||||||
@ -364,7 +619,14 @@ def _print_available_commands() -> None:
|
|||||||
' The same can be\n'
|
' The same can be\n'
|
||||||
' achieved by passing --submodule-parent to'
|
' achieved by passing --submodule-parent to'
|
||||||
' the \'create\'\n'
|
' the \'create\'\n'
|
||||||
' command.'
|
' command.\n'
|
||||||
|
f' {bgn}fset-copy [src, dst]{end} Copy feature-set src to dst.'
|
||||||
|
' Replaces variations of src\n'
|
||||||
|
' feature-set name with dst equivalent,'
|
||||||
|
' though may need\n'
|
||||||
|
' some manual correction afterwards to be'
|
||||||
|
' functional.\n'
|
||||||
|
f' {bgn}fset-delete [name]{end} Delete a feature-set.'
|
||||||
),
|
),
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user