added bascenev1.get_connection_to_host_info_2()

This commit is contained in:
Eric 2023-12-13 22:18:42 -08:00
parent c6f0ecf17e
commit 5cf8065c40
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
54 changed files with 542 additions and 378 deletions

100
.efrocachemap generated
View File

@ -421,18 +421,18 @@
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26", "build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8", "build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55", "build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
"build/assets/ba_data/data/langdata.json": "c6f94f9c1dc833c537d16672d9018b94", "build/assets/ba_data/data/langdata.json": "4a35cc51d1021fa7e525123bcf99043c",
"build/assets/ba_data/data/languages/arabic.json": "00ba700de6c672a56658a6bd1ad27523", "build/assets/ba_data/data/languages/arabic.json": "00ba700de6c672a56658a6bd1ad27523",
"build/assets/ba_data/data/languages/belarussian.json": "7fe38341815ca6ff4d95224196e7a67e", "build/assets/ba_data/data/languages/belarussian.json": "7fe38341815ca6ff4d95224196e7a67e",
"build/assets/ba_data/data/languages/chinese.json": "5761468d25f2bd4e79921826cebd572b", "build/assets/ba_data/data/languages/chinese.json": "5761468d25f2bd4e79921826cebd572b",
"build/assets/ba_data/data/languages/chinesetraditional.json": "f858da49be0a5374157c627857751078", "build/assets/ba_data/data/languages/chinesetraditional.json": "f858da49be0a5374157c627857751078",
"build/assets/ba_data/data/languages/croatian.json": "766532c67af5bd0144c2d63cab0516fa", "build/assets/ba_data/data/languages/croatian.json": "766532c67af5bd0144c2d63cab0516fa",
"build/assets/ba_data/data/languages/czech.json": "93c5fe0d884d95435da6c675f64e30e0", "build/assets/ba_data/data/languages/czech.json": "cd21ad8c6b8e9ed700284cf1e1aecbf8",
"build/assets/ba_data/data/languages/danish.json": "3fd69080783d5c9dcc0af737f02b6f1e", "build/assets/ba_data/data/languages/danish.json": "3fd69080783d5c9dcc0af737f02b6f1e",
"build/assets/ba_data/data/languages/dutch.json": "22b44a33bf81142ba2befad14eb5746e", "build/assets/ba_data/data/languages/dutch.json": "22b44a33bf81142ba2befad14eb5746e",
"build/assets/ba_data/data/languages/english.json": "bd43b77b1ccca059573acbde148b4767", "build/assets/ba_data/data/languages/english.json": "bd43b77b1ccca059573acbde148b4767",
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880", "build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
"build/assets/ba_data/data/languages/filipino.json": "afbda3adf14555e1567ee63c32e340e7", "build/assets/ba_data/data/languages/filipino.json": "0f5ad7c06db70027b116dfd9324bdf67",
"build/assets/ba_data/data/languages/french.json": "49ff6d211537b8003b8241438dca661d", "build/assets/ba_data/data/languages/french.json": "49ff6d211537b8003b8241438dca661d",
"build/assets/ba_data/data/languages/german.json": "450fa41ae264f29a5d1af22143d0d0ad", "build/assets/ba_data/data/languages/german.json": "450fa41ae264f29a5d1af22143d0d0ad",
"build/assets/ba_data/data/languages/gibberish.json": "9aae526303a22372fe9b4cf1781520ef", "build/assets/ba_data/data/languages/gibberish.json": "9aae526303a22372fe9b4cf1781520ef",
@ -445,12 +445,12 @@
"build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38", "build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38",
"build/assets/ba_data/data/languages/persian.json": "d742f4a6d3c3555031102b21abdcbb5b", "build/assets/ba_data/data/languages/persian.json": "d742f4a6d3c3555031102b21abdcbb5b",
"build/assets/ba_data/data/languages/polish.json": "b9a58b70ed5e99d8b7fa2392b2eb0cda", "build/assets/ba_data/data/languages/polish.json": "b9a58b70ed5e99d8b7fa2392b2eb0cda",
"build/assets/ba_data/data/languages/portuguese.json": "556af4e8170356ad239412e1743e20d5", "build/assets/ba_data/data/languages/portuguese.json": "e3adc6c04486d21e84019a0b03ce11b1",
"build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826", "build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826",
"build/assets/ba_data/data/languages/russian.json": "e120993371f52edd2d99f2236188933c", "build/assets/ba_data/data/languages/russian.json": "e120993371f52edd2d99f2236188933c",
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69", "build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
"build/assets/ba_data/data/languages/slovak.json": "27962d53dc3f7dd4e877cd40faafeeef", "build/assets/ba_data/data/languages/slovak.json": "27962d53dc3f7dd4e877cd40faafeeef",
"build/assets/ba_data/data/languages/spanish.json": "80ea58bd3295a0252b7fdac9154aa22f", "build/assets/ba_data/data/languages/spanish.json": "1d14210b4eefb48130608bd0495b7900",
"build/assets/ba_data/data/languages/swedish.json": "5142a96597d17d8344be96a603da64ac", "build/assets/ba_data/data/languages/swedish.json": "5142a96597d17d8344be96a603da64ac",
"build/assets/ba_data/data/languages/tamil.json": "b4de1a2851afe4869c82e9acd94cd89c", "build/assets/ba_data/data/languages/tamil.json": "b4de1a2851afe4869c82e9acd94cd89c",
"build/assets/ba_data/data/languages/thai.json": "77755219bbf5fb7eea0d6b226684f403", "build/assets/ba_data/data/languages/thai.json": "77755219bbf5fb7eea0d6b226684f403",
@ -4060,50 +4060,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": "8561660678904509458b80bb4b62d8ea", "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "6135aeb242afaf9d1114810a67c89cec",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "f2e7de4723ce8fb6984a5bbd9ac93aa6", "build/prefab/full/linux_arm64_gui/release/ballisticakit": "bbbbb14d42ed6eb0c5eb56867b7fb870",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "af1ade2cc275dacc7e1793383d766f3d", "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "cd28f9cc4652736a31c677fc4e5dbaf1",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "bb806faa941b6c3c7834383264cf8571", "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "239c608cc52c0320210e56ad6abe57a5",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "648bfaca6487ff13cd27a31e317878f0", "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "e76d67cacf1393d33796d6b6b1bf1413",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "38501876d5009ecaa936994ec6fbb3a2", "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "a7eaa8dc4d859ef7a735483b04ccec4a",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "f7d354aded26684974b4d0fbb8725762", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "7a2eef42da34a35ddcc2fd7c66843b1b",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "f6ceb8135fe4fb9aa7fc13fb1b835077", "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "694599ac6a967b2ed383b27bf8093e5b",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "402cb0d5a0abecfa9e578f3801b15e59", "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "c91cbab6a07affa22e0612210f8b807c",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "4eae3e6ade00be0224839bfc16351d2c", "build/prefab/full/mac_arm64_gui/release/ballisticakit": "d460f7a3909f92d5dbf752e4521a9fbc",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "c6dd9b6cf876db50aa8d0cc0cc80efa4", "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "0a0abfe75bc987e7b65a3cfa106e8353",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "79d19536ed7de918c947c5095286b8ce", "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "8f21405b29f2b2ab01323d711492cca0",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "409140e2c39941dbc66088417399d5ea", "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "96dc73e819f41f99a1b2dbb45f79d551",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "1a25fd7e3c5b94a294ce769083b71751", "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "c79ac51cd2deabb1c2d0acddeaf81c30",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "7bfbb50681473702f286a50e56277b93", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "f06ec14e8c3106be9df91af7da621dc9",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "37ce7d3b865c0b58161c2d4ccdb54256", "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "f389f9a7b1afc81f76787722340cfa9c",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "728dfc083916d7199dee1e75ad12e9fc", "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "c7dab78aac11cb1430d8456d5d48107a",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "fbf59de05d7e121d9c5dd164939228dc", "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "67e29852dfee2e63e179cfebf608ef26",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "1eb456e1b1c4d215912809950d938c1a", "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "9778f8faf91c9993fbf3015bd4554a87",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "65f507699fed78fcfa12e3e63af2bf8b", "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "73477bd15b9e3834314fd878c9e108d4",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "4f5d3cafbea651078c1721684b61033a", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "fb9b8443c1b4cccad749df7d6328220f",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "7436c575aee1f9d112d41f18e2ae6b22", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "384fb7fd55ad5a6cdbb662da1ec402ab",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "4f5d3cafbea651078c1721684b61033a", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "fb9b8443c1b4cccad749df7d6328220f",
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "7436c575aee1f9d112d41f18e2ae6b22", "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "384fb7fd55ad5a6cdbb662da1ec402ab",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "3ffcb35eb71566fefb7d9ad2589b37b4", "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "bc7d0811bcd87156ebf5292a38a1c350",
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "ce9de33efccb9aa1e301fe4f11e6b1c1", "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "bb32f45054b6999300bf8b41d6a4b402",
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "3ffcb35eb71566fefb7d9ad2589b37b4", "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "bc7d0811bcd87156ebf5292a38a1c350",
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "ce9de33efccb9aa1e301fe4f11e6b1c1", "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "bb32f45054b6999300bf8b41d6a4b402",
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "9d674b5e8a8357b9462a65359611ea45", "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "8d9a1505bf397f4902baabed7c1cf438",
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "e6d1c0b9bf27c34968e512c5db8e7de5", "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "f4d9c115e22dd81e36d1c5baeac8d848",
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "9d674b5e8a8357b9462a65359611ea45", "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "8d9a1505bf397f4902baabed7c1cf438",
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "e6d1c0b9bf27c34968e512c5db8e7de5", "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "f4d9c115e22dd81e36d1c5baeac8d848",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "910b5e39fe4ba5bb849505c578efe3ec", "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "fb72c92ec6ec0e1c8f4ced32abd86505",
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "2d9e14f7cfe50b1dc51e5e9eae05b5fd", "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "131aab20cfe77fe89c3f452a855f1e68",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "b83a67eeaed0fc99bf995767a8150e5d", "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "ee10cdc9f9a861e2be0f1a208c0ca0fe",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "2d9e14f7cfe50b1dc51e5e9eae05b5fd", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "131aab20cfe77fe89c3f452a855f1e68",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "f6a855e83d7816e73d9859ff9e508190", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "678fabc6dfd6f401ee8942d088ee9181",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "6cd203dce2718e0eded672c83c51506a", "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "e092d2aed8464a61a623d79ca25308d8",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "a1f81d6527bba562c3626e520ab8aa2d", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "6b658f49be396ad645c5e57464739a3b",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "8b6a8b19f73b67413612185aa2d9ca5d", "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "9d79a56403a6d806ff131a7de664dfa7",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "2534af31cf9f8a86ddb7c92b0184f4b2", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "e831a26d2c28e862d51e24393d158c99",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "0cf7fb12f97a3f8176462ec5d1ddb992", "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "46fe1c89bcc75c781729ec9e5491c610",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "4afbbfa78e25e932d9392a1bd6bacc52", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "9c6278d7df3ce4db2ffe7794a0fd35b7",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "a0ba1ed33b7a83543b51f24a96941dfa", "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "110c35a17b462864075800756b5e541a",
"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": "28323912b56ec07701eda3d41a6a4101", "src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "72bfed2cce8ff19741989dec28302f3f", "src/ballistica/base/mgen/pyembed/binding_base.inc": "72bfed2cce8ff19741989dec28302f3f",
@ -4112,7 +4112,7 @@
"src/ballistica/core/mgen/pyembed/binding_core.inc": "9d0a3c9636138e35284923e0c8311c69", "src/ballistica/core/mgen/pyembed/binding_core.inc": "9d0a3c9636138e35284923e0c8311c69",
"src/ballistica/core/mgen/pyembed/env.inc": "8be46e5818f360d10b7b0224a9e91d07", "src/ballistica/core/mgen/pyembed/env.inc": "8be46e5818f360d10b7b0224a9e91d07",
"src/ballistica/core/mgen/python_modules_monolithic.h": "fb967ed1c7db0c77d8deb4f00a7103c5", "src/ballistica/core/mgen/python_modules_monolithic.h": "fb967ed1c7db0c77d8deb4f00a7103c5",
"src/ballistica/scene_v1/mgen/pyembed/binding_scene_v1.inc": "d80f970053099b3044204bfe29ddefce", "src/ballistica/scene_v1/mgen/pyembed/binding_scene_v1.inc": "c25b263f2a31fb5ebe057db07d144879",
"src/ballistica/template_fs/mgen/pyembed/binding_template_fs.inc": "44a45492db057bf7f7158c3b0fa11f0f", "src/ballistica/template_fs/mgen/pyembed/binding_template_fs.inc": "44a45492db057bf7f7158c3b0fa11f0f",
"src/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc": "f5f054050d2b2fcd3763a4833fb32269" "src/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc": "f5f054050d2b2fcd3763a4833fb32269"
} }

View File

@ -21,7 +21,6 @@
<excludeFolder url="file://$MODULE_DIR$/ballisticakit-android" /> <excludeFolder url="file://$MODULE_DIR$/ballisticakit-android" />
<excludeFolder url="file://$MODULE_DIR$/ballisticakit-cmake" /> <excludeFolder url="file://$MODULE_DIR$/ballisticakit-cmake" />
<excludeFolder url="file://$MODULE_DIR$/ballisticakit-ios.xcodeproj" /> <excludeFolder url="file://$MODULE_DIR$/ballisticakit-ios.xcodeproj" />
<excludeFolder url="file://$MODULE_DIR$/ballisticakit-mac.xcodeproj" />
<excludeFolder url="file://$MODULE_DIR$/ballisticakit-windows" /> <excludeFolder url="file://$MODULE_DIR$/ballisticakit-windows" />
<excludeFolder url="file://$MODULE_DIR$/ballisticakit-windows-oculus" /> <excludeFolder url="file://$MODULE_DIR$/ballisticakit-windows-oculus" />
<excludeFolder url="file://$MODULE_DIR$/ballisticakit-xcode" /> <excludeFolder url="file://$MODULE_DIR$/ballisticakit-xcode" />

View File

@ -1,4 +1,6 @@
### 1.7.31 (build 21700, api 8, 2023-12-09) ### 1.7.31 (build 21707, api 8, 2023-12-13)
- added `bascenev1.get_connection_to_host_info_2()` which is an improved
type-safe version of `bascenev1.get_connection_to_host_info()`.
### 1.7.30 (build 21697, api 8, 2023-12-08) ### 1.7.30 (build 21697, api 8, 2023-12-08)
- Continued work on the big 1.7.28 update. - Continued work on the big 1.7.28 update.

View File

@ -14,7 +14,6 @@
<file path="$PROJECT_DIR$/../ballisticakit-android" /> <file path="$PROJECT_DIR$/../ballisticakit-android" />
<file path="$PROJECT_DIR$/.idea" /> <file path="$PROJECT_DIR$/.idea" />
<file path="$PROJECT_DIR$/../ballisticakit-ios.xcodeproj" /> <file path="$PROJECT_DIR$/../ballisticakit-ios.xcodeproj" />
<file path="$PROJECT_DIR$/../ballisticakit-mac.xcodeproj" />
<file path="$PROJECT_DIR$/../ballisticakit-windows" /> <file path="$PROJECT_DIR$/../ballisticakit-windows" />
<file path="$PROJECT_DIR$/../ballisticakit-xcode" /> <file path="$PROJECT_DIR$/../ballisticakit-xcode" />
<file path="$PROJECT_DIR$/../build" /> <file path="$PROJECT_DIR$/../build" />

View File

@ -152,7 +152,6 @@ ctx.filter_dirs = {
'ballisticakit-cmake', 'ballisticakit-cmake',
'ballisticakit-xcode/BallisticaKit.xcodeproj', 'ballisticakit-xcode/BallisticaKit.xcodeproj',
'ballisticakit-ios.xcodeproj', 'ballisticakit-ios.xcodeproj',
'ballisticakit-mac.xcodeproj',
'config', 'config',
'src/assets/pdoc', 'src/assets/pdoc',
} }

View File

@ -20,7 +20,6 @@
"ba_data/python/babase/__pycache__/_error.cpython-311.opt-1.pyc", "ba_data/python/babase/__pycache__/_error.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_general.cpython-311.opt-1.pyc", "ba_data/python/babase/__pycache__/_general.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_hooks.cpython-311.opt-1.pyc", "ba_data/python/babase/__pycache__/_hooks.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_keyboard.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_language.cpython-311.opt-1.pyc", "ba_data/python/babase/__pycache__/_language.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_login.cpython-311.opt-1.pyc", "ba_data/python/babase/__pycache__/_login.cpython-311.opt-1.pyc",
"ba_data/python/babase/__pycache__/_math.cpython-311.opt-1.pyc", "ba_data/python/babase/__pycache__/_math.cpython-311.opt-1.pyc",
@ -50,7 +49,6 @@
"ba_data/python/babase/_error.py", "ba_data/python/babase/_error.py",
"ba_data/python/babase/_general.py", "ba_data/python/babase/_general.py",
"ba_data/python/babase/_hooks.py", "ba_data/python/babase/_hooks.py",
"ba_data/python/babase/_keyboard.py",
"ba_data/python/babase/_language.py", "ba_data/python/babase/_language.py",
"ba_data/python/babase/_login.py", "ba_data/python/babase/_login.py",
"ba_data/python/babase/_math.py", "ba_data/python/babase/_math.py",
@ -152,6 +150,7 @@
"ba_data/python/bascenev1/__pycache__/_messages.cpython-311.opt-1.pyc", "ba_data/python/bascenev1/__pycache__/_messages.cpython-311.opt-1.pyc",
"ba_data/python/bascenev1/__pycache__/_multiteamsession.cpython-311.opt-1.pyc", "ba_data/python/bascenev1/__pycache__/_multiteamsession.cpython-311.opt-1.pyc",
"ba_data/python/bascenev1/__pycache__/_music.cpython-311.opt-1.pyc", "ba_data/python/bascenev1/__pycache__/_music.cpython-311.opt-1.pyc",
"ba_data/python/bascenev1/__pycache__/_net.cpython-311.opt-1.pyc",
"ba_data/python/bascenev1/__pycache__/_nodeactor.cpython-311.opt-1.pyc", "ba_data/python/bascenev1/__pycache__/_nodeactor.cpython-311.opt-1.pyc",
"ba_data/python/bascenev1/__pycache__/_player.cpython-311.opt-1.pyc", "ba_data/python/bascenev1/__pycache__/_player.cpython-311.opt-1.pyc",
"ba_data/python/bascenev1/__pycache__/_playlist.cpython-311.opt-1.pyc", "ba_data/python/bascenev1/__pycache__/_playlist.cpython-311.opt-1.pyc",
@ -186,6 +185,7 @@
"ba_data/python/bascenev1/_messages.py", "ba_data/python/bascenev1/_messages.py",
"ba_data/python/bascenev1/_multiteamsession.py", "ba_data/python/bascenev1/_multiteamsession.py",
"ba_data/python/bascenev1/_music.py", "ba_data/python/bascenev1/_music.py",
"ba_data/python/bascenev1/_net.py",
"ba_data/python/bascenev1/_nodeactor.py", "ba_data/python/bascenev1/_nodeactor.py",
"ba_data/python/bascenev1/_player.py", "ba_data/python/bascenev1/_player.py",
"ba_data/python/bascenev1/_playlist.py", "ba_data/python/bascenev1/_playlist.py",
@ -352,10 +352,12 @@
"ba_data/python/bauiv1/__init__.py", "ba_data/python/bauiv1/__init__.py",
"ba_data/python/bauiv1/__pycache__/__init__.cpython-311.opt-1.pyc", "ba_data/python/bauiv1/__pycache__/__init__.cpython-311.opt-1.pyc",
"ba_data/python/bauiv1/__pycache__/_hooks.cpython-311.opt-1.pyc", "ba_data/python/bauiv1/__pycache__/_hooks.cpython-311.opt-1.pyc",
"ba_data/python/bauiv1/__pycache__/_keyboard.cpython-311.opt-1.pyc",
"ba_data/python/bauiv1/__pycache__/_subsystem.cpython-311.opt-1.pyc", "ba_data/python/bauiv1/__pycache__/_subsystem.cpython-311.opt-1.pyc",
"ba_data/python/bauiv1/__pycache__/_uitypes.cpython-311.opt-1.pyc", "ba_data/python/bauiv1/__pycache__/_uitypes.cpython-311.opt-1.pyc",
"ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-311.opt-1.pyc", "ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-311.opt-1.pyc",
"ba_data/python/bauiv1/_hooks.py", "ba_data/python/bauiv1/_hooks.py",
"ba_data/python/bauiv1/_keyboard.py",
"ba_data/python/bauiv1/_subsystem.py", "ba_data/python/bauiv1/_subsystem.py",
"ba_data/python/bauiv1/_uitypes.py", "ba_data/python/bauiv1/_uitypes.py",
"ba_data/python/bauiv1/onscreenkeyboard.py", "ba_data/python/bauiv1/onscreenkeyboard.py",

View File

@ -178,7 +178,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \
$(BUILD_DIR)/ba_data/python/babase/_error.py \ $(BUILD_DIR)/ba_data/python/babase/_error.py \
$(BUILD_DIR)/ba_data/python/babase/_general.py \ $(BUILD_DIR)/ba_data/python/babase/_general.py \
$(BUILD_DIR)/ba_data/python/babase/_hooks.py \ $(BUILD_DIR)/ba_data/python/babase/_hooks.py \
$(BUILD_DIR)/ba_data/python/babase/_keyboard.py \
$(BUILD_DIR)/ba_data/python/babase/_language.py \ $(BUILD_DIR)/ba_data/python/babase/_language.py \
$(BUILD_DIR)/ba_data/python/babase/_login.py \ $(BUILD_DIR)/ba_data/python/babase/_login.py \
$(BUILD_DIR)/ba_data/python/babase/_math.py \ $(BUILD_DIR)/ba_data/python/babase/_math.py \
@ -237,6 +236,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
$(BUILD_DIR)/ba_data/python/bascenev1/_messages.py \ $(BUILD_DIR)/ba_data/python/bascenev1/_messages.py \
$(BUILD_DIR)/ba_data/python/bascenev1/_multiteamsession.py \ $(BUILD_DIR)/ba_data/python/bascenev1/_multiteamsession.py \
$(BUILD_DIR)/ba_data/python/bascenev1/_music.py \ $(BUILD_DIR)/ba_data/python/bascenev1/_music.py \
$(BUILD_DIR)/ba_data/python/bascenev1/_net.py \
$(BUILD_DIR)/ba_data/python/bascenev1/_nodeactor.py \ $(BUILD_DIR)/ba_data/python/bascenev1/_nodeactor.py \
$(BUILD_DIR)/ba_data/python/bascenev1/_player.py \ $(BUILD_DIR)/ba_data/python/bascenev1/_player.py \
$(BUILD_DIR)/ba_data/python/bascenev1/_playlist.py \ $(BUILD_DIR)/ba_data/python/bascenev1/_playlist.py \
@ -326,6 +326,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
$(BUILD_DIR)/ba_data/python/batemplatefs/_subsystem.py \ $(BUILD_DIR)/ba_data/python/batemplatefs/_subsystem.py \
$(BUILD_DIR)/ba_data/python/bauiv1/__init__.py \ $(BUILD_DIR)/ba_data/python/bauiv1/__init__.py \
$(BUILD_DIR)/ba_data/python/bauiv1/_hooks.py \ $(BUILD_DIR)/ba_data/python/bauiv1/_hooks.py \
$(BUILD_DIR)/ba_data/python/bauiv1/_keyboard.py \
$(BUILD_DIR)/ba_data/python/bauiv1/_subsystem.py \ $(BUILD_DIR)/ba_data/python/bauiv1/_subsystem.py \
$(BUILD_DIR)/ba_data/python/bauiv1/_uitypes.py \ $(BUILD_DIR)/ba_data/python/bauiv1/_uitypes.py \
$(BUILD_DIR)/ba_data/python/bauiv1/onscreenkeyboard.py \ $(BUILD_DIR)/ba_data/python/bauiv1/onscreenkeyboard.py \
@ -452,7 +453,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_error.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_error.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_general.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_general.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_hooks.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_hooks.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_keyboard.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_language.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_language.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_login.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_login.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/babase/__pycache__/_math.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_math.cpython-311.opt-1.pyc \
@ -511,6 +511,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_messages.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_messages.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_multiteamsession.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_multiteamsession.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_music.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_music.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_net.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_nodeactor.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_nodeactor.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_player.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_player.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_playlist.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_playlist.cpython-311.opt-1.pyc \
@ -600,6 +601,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
$(BUILD_DIR)/ba_data/python/batemplatefs/__pycache__/_subsystem.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/batemplatefs/__pycache__/_subsystem.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/__init__.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/__init__.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_hooks.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_hooks.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_keyboard.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_subsystem.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_subsystem.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_uitypes.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_uitypes.cpython-311.opt-1.pyc \
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-311.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-311.opt-1.pyc \

View File

@ -154,7 +154,6 @@ from babase._general import (
getclass, getclass,
get_type_name, get_type_name,
) )
from babase._keyboard import Keyboard
from babase._language import Lstr, LanguageSubsystem from babase._language import Lstr, LanguageSubsystem
from babase._login import LoginAdapter, LoginInfo from babase._login import LoginAdapter, LoginInfo
@ -261,7 +260,6 @@ __all__ = [
'is_point_in_box', 'is_point_in_box',
'is_running_on_fire_tv', 'is_running_on_fire_tv',
'is_xcode_build', 'is_xcode_build',
'Keyboard',
'LanguageSubsystem', 'LanguageSubsystem',
'lock_all_input', 'lock_all_input',
'LoginAdapter', 'LoginAdapter',

View File

@ -19,7 +19,7 @@ if TYPE_CHECKING:
from babase._login import LoginAdapter, LoginInfo from babase._login import LoginAdapter, LoginInfo
DEBUG_LOG = _babase.temp_testing() DEBUG_LOG = False
class AccountV2Subsystem: class AccountV2Subsystem:

View File

@ -31,6 +31,7 @@ class AppMode:
AppExperience associated with the AppMode must be supported by AppExperience associated with the AppMode must be supported by
the current app and runtime environment. the current app and runtime environment.
""" """
# FIXME: check AppExperience.
return cls._supports_intent(intent) return cls._supports_intent(intent)
@classmethod @classmethod

View File

@ -325,7 +325,7 @@ def dump_app_state(
) )
def log_dumped_app_state() -> None: def log_dumped_app_state(from_previous_run: bool = False) -> None:
"""If an app-state dump exists, log it and clear it. No-op otherwise.""" """If an app-state dump exists, log it and clear it. No-op otherwise."""
try: try:
@ -352,8 +352,13 @@ def log_dumped_app_state() -> None:
metadata = dataclass_from_json(DumpedAppStateMetadata, appstatedata) metadata = dataclass_from_json(DumpedAppStateMetadata, appstatedata)
header = (
'Found app state dump from previous app run'
if from_previous_run
else 'App state dump'
)
out += ( out += (
f'App state dump:\nReason: {metadata.reason}\n' f'{header}:\nReason: {metadata.reason}\n'
f'Time: {metadata.app_time:.2f}' f'Time: {metadata.app_time:.2f}'
) )
tbpath = os.path.join( tbpath = os.path.join(
@ -383,7 +388,7 @@ class AppHealthMonitor(AppSubsystem):
def on_app_loading(self) -> None: def on_app_loading(self) -> None:
# If any traceback dumps happened last run, log and clear them. # If any traceback dumps happened last run, log and clear them.
log_dumped_app_state() log_dumped_app_state(from_previous_run=True)
def _app_monitor_thread_main(self) -> None: def _app_monitor_thread_main(self) -> None:
_babase.set_thread_name('ballistica app-monitor') _babase.set_thread_name('ballistica app-monitor')

View File

@ -17,7 +17,7 @@ if TYPE_CHECKING:
from typing import Callable from typing import Callable
DEBUG_LOG = _babase.temp_testing() DEBUG_LOG = False
@dataclass @dataclass

View File

@ -24,6 +24,8 @@ if TYPE_CHECKING:
# instead of these or to make the meta system aware of arbitrary classes. # instead of these or to make the meta system aware of arbitrary classes.
EXPORT_CLASS_NAME_SHORTCUTS: dict[str, str] = { EXPORT_CLASS_NAME_SHORTCUTS: dict[str, str] = {
'plugin': 'babase.Plugin', 'plugin': 'babase.Plugin',
# DEPRECATED as of 12/2023. Currently am warning if finding these
# but should take this out eventually.
'keyboard': 'babase.Keyboard', 'keyboard': 'babase.Keyboard',
} }
@ -414,30 +416,27 @@ class DirectoryScan:
if export_class_name is not None: if export_class_name is not None:
classname = modulename + '.' + export_class_name classname = modulename + '.' + export_class_name
# Since we'll soon have multiple versions of 'game' # Migrating away from the 'keyboard' name shortcut
# classes we need to migrate people to using base # since it's specific to bauiv1; warn if we find it.
# class names for them. if exporttypestr == 'keyboard':
if exporttypestr == 'game':
logging.warning( logging.warning(
"metascan: %s:%d: '# ba_meta export" "metascan: %s:%d: '# ba_meta export"
" game' tag should be replaced by '# ba_meta" " keyboard' tag should be replaced by '# ba_meta"
" export bascenev1.GameActivity'.", " export bauiv1.Keyboard'.",
subpath, subpath,
lindex + 1, lindex + 1,
) )
self.results.announce_errors_occurred = True self.results.announce_errors_occurred = True
else:
# If export type is one of our shortcuts, sub in the # If export type is one of our shortcuts, sub in the
# actual class path. Otherwise assume its a classpath # actual class path. Otherwise assume its a classpath
# itself. # itself.
exporttype = EXPORT_CLASS_NAME_SHORTCUTS.get( exporttype = EXPORT_CLASS_NAME_SHORTCUTS.get(exporttypestr)
exporttypestr if exporttype is None:
) exporttype = exporttypestr
if exporttype is None: self.results.exports.setdefault(exporttype, []).append(
exporttype = exporttypestr classname
self.results.exports.setdefault(exporttype, []).append( )
classname
)
def _get_export_class_name( def _get_export_class_name(
self, subpath: Path, lines: list[str], lindex: int self, subpath: Path, lines: list[str], lindex: int

View File

@ -97,7 +97,7 @@ class AdsSubsystem:
show = True show = True
# No ads without net-connections, etc. # No ads without net-connections, etc.
if not bauiv1.can_show_ad(): if not plus.can_show_ad():
show = False show = False
if classic.accounts.have_pro(): if classic.accounts.have_pro():
show = False # Pro disables interstitials. show = False # Pro disables interstitials.
@ -135,7 +135,7 @@ class AdsSubsystem:
# ad-show-threshold and see if we should *actually* show # ad-show-threshold and see if we should *actually* show
# (we reach our threshold faster the longer we've been # (we reach our threshold faster the longer we've been
# playing). # playing).
base = 'ads' if bauiv1.has_video_ads() else 'ads2' base = 'ads' if plus.has_video_ads() else 'ads2'
min_lc = plus.get_v1_account_misc_read_val(base + '.minLC', 0.0) min_lc = plus.get_v1_account_misc_read_val(base + '.minLC', 0.0)
max_lc = plus.get_v1_account_misc_read_val(base + '.maxLC', 5.0) max_lc = plus.get_v1_account_misc_read_val(base + '.maxLC', 5.0)
min_lc_scale = plus.get_v1_account_misc_read_val( min_lc_scale = plus.get_v1_account_misc_read_val(

View File

@ -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 = 21700 TARGET_BALLISTICA_BUILD = 21707
TARGET_BALLISTICA_VERSION = '1.7.31' TARGET_BALLISTICA_VERSION = '1.7.31'

View File

@ -249,3 +249,18 @@ class PlusSubsystem(AppSubsystem):
) -> None: ) -> None:
"""(internal)""" """(internal)"""
return _baplus.tournament_query(callback, args) return _baplus.tournament_query(callback, args)
@staticmethod
def have_incentivized_ad() -> bool:
"""Is an incentivized ad available?"""
return _baplus.have_incentivized_ad()
@staticmethod
def has_video_ads() -> bool:
"""Are video ads available?"""
return _baplus.has_video_ads()
@staticmethod
def can_show_ad() -> bool:
"""Can we show an ad?"""
return _baplus.can_show_ad()

View File

@ -78,6 +78,7 @@ from _bascenev1 import (
end_host_scanning, end_host_scanning,
get_chat_messages, get_chat_messages,
get_connection_to_host_info, get_connection_to_host_info,
get_connection_to_host_info_2,
get_foreground_host_activity, get_foreground_host_activity,
get_foreground_host_session, get_foreground_host_session,
get_game_port, get_game_port,
@ -202,6 +203,7 @@ from bascenev1._multiteamsession import (
DEFAULT_TEAM_NAMES, DEFAULT_TEAM_NAMES,
) )
from bascenev1._music import MusicType, setmusic from bascenev1._music import MusicType, setmusic
from bascenev1._net import HostInfo
from bascenev1._nodeactor import NodeActor from bascenev1._nodeactor import NodeActor
from bascenev1._powerup import get_default_powerup_distribution from bascenev1._powerup import get_default_powerup_distribution
from bascenev1._profile import ( from bascenev1._profile import (
@ -303,6 +305,7 @@ __all__ = [
'GameTip', 'GameTip',
'get_chat_messages', 'get_chat_messages',
'get_connection_to_host_info', 'get_connection_to_host_info',
'get_connection_to_host_info_2',
'get_default_free_for_all_playlist', 'get_default_free_for_all_playlist',
'get_default_teams_playlist', 'get_default_teams_playlist',
'get_default_powerup_distribution', 'get_default_powerup_distribution',
@ -338,6 +341,7 @@ __all__ = [
'have_connected_clients', 'have_connected_clients',
'have_touchscreen_input', 'have_touchscreen_input',
'HitMessage', 'HitMessage',
'HostInfo',
'host_scan_cycle', 'host_scan_cycle',
'ImpactDamageMessage', 'ImpactDamageMessage',
'increment_analytics_count', 'increment_analytics_count',

View File

@ -0,0 +1,24 @@
# Released under the MIT License. See LICENSE for details.
#
"""Functionality related to net play."""
from __future__ import annotations
from typing import TYPE_CHECKING
from dataclasses import dataclass
if TYPE_CHECKING:
pass
@dataclass
class HostInfo:
"""Info about a host."""
name: str
build_number: int
# Note this can be None for non-ip hosts such as bluetooth.
address: str | None
# Note this can be None for non-ip hosts such as bluetooth.
port: int | None

View File

@ -62,7 +62,6 @@ from babase import (
is_browser_likely_available, is_browser_likely_available,
is_running_on_fire_tv, is_running_on_fire_tv,
is_xcode_build, is_xcode_build,
Keyboard,
lock_all_input, lock_all_input,
LoginAdapter, LoginAdapter,
LoginInfo, LoginInfo,
@ -94,7 +93,6 @@ from babase import (
from _bauiv1 import ( from _bauiv1 import (
buttonwidget, buttonwidget,
can_show_ad,
checkboxwidget, checkboxwidget,
columnwidget, columnwidget,
containerwidget, containerwidget,
@ -103,8 +101,6 @@ from _bauiv1 import (
getmesh, getmesh,
getsound, getsound,
gettexture, gettexture,
has_video_ads,
have_incentivized_ad,
hscrollwidget, hscrollwidget,
imagewidget, imagewidget,
is_party_icon_visible, is_party_icon_visible,
@ -125,6 +121,7 @@ from _bauiv1 import (
Widget, Widget,
widget, widget,
) )
from bauiv1._keyboard import Keyboard
from bauiv1._uitypes import Window, uicleanupcheck from bauiv1._uitypes import Window, uicleanupcheck
from bauiv1._subsystem import UIV1Subsystem from bauiv1._subsystem import UIV1Subsystem
@ -144,7 +141,6 @@ __all__ = [
'AppTimer', 'AppTimer',
'buttonwidget', 'buttonwidget',
'Call', 'Call',
'can_show_ad',
'fullscreen_control_available', 'fullscreen_control_available',
'fullscreen_control_get', 'fullscreen_control_get',
'fullscreen_control_key_shortcut', 'fullscreen_control_key_shortcut',
@ -178,8 +174,6 @@ __all__ = [
'getmesh', 'getmesh',
'getsound', 'getsound',
'gettexture', 'gettexture',
'has_video_ads',
'have_incentivized_ad',
'have_permission', 'have_permission',
'hscrollwidget', 'hscrollwidget',
'imagewidget', 'imagewidget',

View File

@ -12,6 +12,7 @@ from typing import TYPE_CHECKING
import babase import babase
import _bauiv1 import _bauiv1
from bauiv1._keyboard import Keyboard
from bauiv1._uitypes import Window from bauiv1._uitypes import Window
if TYPE_CHECKING: if TYPE_CHECKING:
@ -252,9 +253,7 @@ class OnScreenKeyboardWindow(Window):
# Show change instructions only if we have more than one # Show change instructions only if we have more than one
# keyboard option. # keyboard option.
keyboards = ( keyboards = (
babase.app.meta.scanresults.exports_of_class( babase.app.meta.scanresults.exports_of_class(Keyboard)
babase.Keyboard
)
if babase.app.meta.scanresults is not None if babase.app.meta.scanresults is not None
else [] else []
) )
@ -286,10 +285,10 @@ class OnScreenKeyboardWindow(Window):
def _get_keyboard(self) -> bui.Keyboard: def _get_keyboard(self) -> bui.Keyboard:
assert babase.app.meta.scanresults is not None assert babase.app.meta.scanresults is not None
classname = babase.app.meta.scanresults.exports_of_class( classname = babase.app.meta.scanresults.exports_of_class(Keyboard)[
babase.Keyboard self._keyboard_index
)[self._keyboard_index] ]
kbclass = babase.getclass(classname, babase.Keyboard) kbclass = babase.getclass(classname, Keyboard)
return kbclass() return kbclass()
def _refresh(self) -> None: def _refresh(self) -> None:
@ -384,9 +383,7 @@ class OnScreenKeyboardWindow(Window):
def _next_keyboard(self) -> None: def _next_keyboard(self) -> None:
assert babase.app.meta.scanresults is not None assert babase.app.meta.scanresults is not None
kbexports = babase.app.meta.scanresults.exports_of_class( kbexports = babase.app.meta.scanresults.exports_of_class(Keyboard)
babase.Keyboard
)
self._keyboard_index = (self._keyboard_index + 1) % len(kbexports) self._keyboard_index = (self._keyboard_index + 1) % len(kbexports)
self._load_keyboard() self._load_keyboard()

View File

@ -415,7 +415,7 @@ class CoopBrowserWindow(bui.Window):
) )
# Decrement time on our tournament buttons. # Decrement time on our tournament buttons.
ads_enabled = bui.have_incentivized_ad() ads_enabled = plus.have_incentivized_ad()
for tbtn in self._tournament_buttons: for tbtn in self._tournament_buttons:
tbtn.time_remaining = max(0, tbtn.time_remaining - 1) tbtn.time_remaining = max(0, tbtn.time_remaining - 1)
if tbtn.time_remaining_value_text is not None: if tbtn.time_remaining_value_text is not None:
@ -430,7 +430,7 @@ class CoopBrowserWindow(bui.Window):
) )
# Also adjust the ad icon visibility. # Also adjust the ad icon visibility.
if tbtn.allow_ads and bui.has_video_ads(): if tbtn.allow_ads and plus.has_video_ads():
bui.imagewidget( bui.imagewidget(
edit=tbtn.entry_fee_ad_image, edit=tbtn.entry_fee_ad_image,
opacity=1.0 if ads_enabled else 0.25, opacity=1.0 if ads_enabled else 0.25,

View File

@ -638,8 +638,8 @@ class TournamentButton:
# Now, if this fee allows ads and we support video ads, show # Now, if this fee allows ads and we support video ads, show
# the 'or ad' version. # the 'or ad' version.
if allow_ads and bui.has_video_ads(): if allow_ads and plus.has_video_ads():
ads_enabled = bui.have_incentivized_ad() ads_enabled = plus.have_incentivized_ad()
bui.imagewidget( bui.imagewidget(
edit=self.entry_fee_ad_image, edit=self.entry_fee_ad_image,
opacity=1.0 if ads_enabled else 0.25, opacity=1.0 if ads_enabled else 0.25,

View File

@ -334,7 +334,7 @@ class GetCurrencyWindow(bui.Window):
tex_scale=1.2, tex_scale=1.2,
) # 19.99-ish ) # 19.99-ish
self._enable_ad_button = bui.has_video_ads() self._enable_ad_button = plus.has_video_ads()
h = self._width * 0.5 + 110.0 h = self._width * 0.5 + 110.0
v = self._height - b_size[1] - 115.0 v = self._height - b_size[1] - 115.0
@ -561,7 +561,7 @@ class GetCurrencyWindow(bui.Window):
next_reward_ad_time next_reward_ad_time
) )
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()
if bui.have_incentivized_ad() and ( if plus.have_incentivized_ad() and (
next_reward_ad_time is None or next_reward_ad_time <= now next_reward_ad_time is None or next_reward_ad_time <= now
): ):
self._ad_button_greyed = False self._ad_button_greyed = False

View File

@ -9,7 +9,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import babase import bauiv1 as bui
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Iterable from typing import Iterable
@ -33,15 +33,15 @@ def split(chars: Iterable[str], maxlen: int) -> list[list[str]]:
def generate_emojis(maxlen: int) -> list[list[str]]: def generate_emojis(maxlen: int) -> list[list[str]]:
"""Generates a lot of UTF8 emojis prepared for babase.Keyboard pages""" """Generates a lot of UTF8 emojis prepared for bui.Keyboard pages"""
all_emojis = split([chr(i) for i in range(0x1F601, 0x1F650)], maxlen) all_emojis = split([chr(i) for i in range(0x1F601, 0x1F650)], maxlen)
all_emojis += split([chr(i) for i in range(0x2702, 0x27B1)], maxlen) all_emojis += split([chr(i) for i in range(0x2702, 0x27B1)], maxlen)
all_emojis += split([chr(i) for i in range(0x1F680, 0x1F6C1)], maxlen) all_emojis += split([chr(i) for i in range(0x1F680, 0x1F6C1)], maxlen)
return all_emojis return all_emojis
# ba_meta export keyboard # ba_meta export bauiv1.Keyboard
class EnglishKeyboard(babase.Keyboard): class EnglishKeyboard(bui.Keyboard):
"""Default English keyboard.""" """Default English keyboard."""
name = 'English' name = 'English'

View File

@ -92,9 +92,10 @@ class PartyWindow(bui.Window):
iconscale=1.2, iconscale=1.2,
) )
info = bs.get_connection_to_host_info() info = bs.get_connection_to_host_info_2()
if info.get('name', '') != '':
title = bui.Lstr(value=info['name']) if info is not None and info.name != '':
title = bui.Lstr(value=info.name)
else: else:
title = bui.Lstr(resource=self._r + '.titleText') title = bui.Lstr(resource=self._r + '.titleText')
@ -481,7 +482,8 @@ class PartyWindow(bui.Window):
kick_str = bui.Lstr(resource='kickText') kick_str = bui.Lstr(resource='kickText')
else: else:
# kick-votes appeared in build 14248 # kick-votes appeared in build 14248
if bs.get_connection_to_host_info().get('build_number', 0) < 14248: info = bs.get_connection_to_host_info_2()
if info is None or info.build_number < 14248:
return return
kick_str = bui.Lstr(resource='kickVoteText') kick_str = bui.Lstr(resource='kickVoteText')
assert bui.app.classic is not None assert bui.app.classic is not None

View File

@ -34,6 +34,7 @@ class TournamentEntryWindow(PopupWindow):
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
assert bui.app.classic is not None assert bui.app.classic is not None
assert bui.app.plus
bui.set_analytics_screen('Tournament Entry Window') bui.set_analytics_screen('Tournament Entry Window')
self._tournament_id = tournament_id self._tournament_id = tournament_id
@ -100,7 +101,7 @@ class TournamentEntryWindow(PopupWindow):
self._launched = False self._launched = False
# Show the ad button only if we support ads *and* it has a level 1 fee. # Show the ad button only if we support ads *and* it has a level 1 fee.
self._do_ad_btn = bui.has_video_ads() and self._allow_ads self._do_ad_btn = bui.app.plus.has_video_ads() and self._allow_ads
x_offs = 0 if self._do_ad_btn else 85 x_offs = 0 if self._do_ad_btn else 85
@ -477,7 +478,7 @@ class TournamentEntryWindow(PopupWindow):
) )
if self._do_ad_btn: if self._do_ad_btn:
enabled = bui.have_incentivized_ad() enabled = plus.have_incentivized_ad()
have_ad_tries_remaining = ( have_ad_tries_remaining = (
self._tournament_info['adTriesRemaining'] is not None self._tournament_info['adTriesRemaining'] is not None
and self._tournament_info['adTriesRemaining'] > 0 and self._tournament_info['adTriesRemaining'] > 0

View File

@ -195,6 +195,12 @@ void BaseFeatureSet::OnAssetsAvailable() {
} }
void BaseFeatureSet::StartApp() { void BaseFeatureSet::StartApp() {
// {
// // TEST - recreate the ID python dumps in its thread tracebacks.
// auto val = PyThread_get_thread_ident();
// printf("MAIN THREAD IS %#018lx\n", val);
// }
BA_PRECONDITION(g_core->InMainThread()); BA_PRECONDITION(g_core->InMainThread());
BA_PRECONDITION(g_base); BA_PRECONDITION(g_base);

View File

@ -50,7 +50,7 @@ void Networking::SendTo(const std::vector<uint8_t>& buffer,
if (sd != -1) { if (sd != -1) {
sendto(sd, (const char*)&buffer[0], sendto(sd, (const char*)&buffer[0],
static_cast_check_fit<socket_send_length_t>(buffer.size()), 0, static_cast_check_fit<socket_send_length_t>(buffer.size()), 0,
addr.GetSockAddr(), addr.GetSockAddrLen()); addr.AsSockAddr(), addr.GetSockAddrLen());
} }
} }

View File

@ -58,8 +58,8 @@ auto BasePlatform::GetPublicDeviceUUID() -> std::string {
// We used to plug version in directly here, but that caused uuids to // We used to plug version in directly here, but that caused uuids to
// shuffle too rapidly during periods of rapid development. This // shuffle too rapidly during periods of rapid development. This
// keeps it more constant. // keeps it more constant.
// __last_rand_uuid_component_shuffle_date__ 2023 6 15 // __last_rand_uuid_component_shuffle_date__ 2023 12 13
auto rand_uuid_component{"JVRWZ82D4WMBO110OA0IFJV7JKMQV8W3"}; auto rand_uuid_component{"7YM96RZHN6ZCPZGTQONULZO1JU5NMMC7"};
inputs.emplace_back(rand_uuid_component); inputs.emplace_back(rand_uuid_component);
auto gil{Python::ScopedInterpreterLock()}; auto gil{Python::ScopedInterpreterLock()};

View File

@ -368,12 +368,64 @@ void CoreFeatureSet::StartSuicideTimer(const std::string& action,
} }
} }
// auto CoreFeatureSet::InMainThread() -> bool { void CoreFeatureSet::RegisterThread(const std::string& name) {
// return std::this_thread::get_id() == main_thread_id; {
// // if (main_event_loop_) { std::scoped_lock lock(thread_info_map_mutex_);
// // return main_event_loop_->ThreadIsCurrent();
// // } // Should be registering each thread just once.
// // return false; assert(thread_info_map_.find(std::this_thread::get_id())
// } == thread_info_map_.end());
thread_info_map_[std::this_thread::get_id()] = name;
}
// Also set the name at the OS leve when possible. Prepend 'ballistica'
// since there's generally lots of other random threads in the mix.
//
// Note that we currently don't do this for our main thread because (on
// Linux at least) that changes the process name we see in top/etc. On
// other platforms we could reconsider, but its generally clear what the
// main thread is anyway in most scenarios.
if (!InMainThread()) {
g_core->platform->SetCurrentThreadName("ballistica " + name);
}
}
void CoreFeatureSet::UnregisterThread() {
std::scoped_lock lock(thread_info_map_mutex_);
auto i = thread_info_map_.find(std::this_thread::get_id());
assert(i != thread_info_map_.end());
if (i != thread_info_map_.end()) {
thread_info_map_.erase(i);
}
}
auto CoreFeatureSet::CurrentThreadName() -> std::string {
if (g_core == nullptr) {
return "unknown(not-yet-inited)";
}
{
std::scoped_lock lock(g_core->thread_info_map_mutex_);
auto i = g_core->thread_info_map_.find(std::this_thread::get_id());
if (i != g_core->thread_info_map_.end()) {
return i->second;
}
}
// Ask pthread for the thread name if we don't have one.
// FIXME - move this to platform.
#if BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS || BA_OSTYPE_LINUX
std::string name = "unknown (sys-name=";
char buffer[256];
int result = pthread_getname_np(pthread_self(), buffer, sizeof(buffer));
if (result == 0) {
name += std::string("\"") + buffer + "\")";
} else {
name += "<error " + std::to_string(result) + ">";
}
return name;
#else
return "unknown";
#endif
}
} // namespace ballistica::core } // namespace ballistica::core

View File

@ -144,6 +144,12 @@ class CoreFeatureSet {
return using_custom_app_python_dir_; return using_custom_app_python_dir_;
} }
/// Register various info about the current thread.
void RegisterThread(const std::string& name);
/// Should be called by a thread before it exits.
void UnregisterThread();
// Subsystems. // Subsystems.
CorePython* const python; CorePython* const python;
CorePlatform* const platform; CorePlatform* const platform;
@ -158,8 +164,6 @@ class CoreFeatureSet {
bool v1_cloud_log_full{}; bool v1_cloud_log_full{};
int master_server_source{}; int master_server_source{};
std::vector<EventLoop*> suspendable_event_loops; std::vector<EventLoop*> suspendable_event_loops;
std::mutex thread_name_map_mutex;
std::unordered_map<std::thread::id, std::string> thread_name_map;
std::mutex v1_cloud_log_mutex; std::mutex v1_cloud_log_mutex;
std::string v1_cloud_log; std::string v1_cloud_log;
@ -173,6 +177,7 @@ class CoreFeatureSet {
auto vr_mode() const { return vr_mode_; } auto vr_mode() const { return vr_mode_; }
auto event_loops_suspended() const { return event_loops_suspended_; } auto event_loops_suspended() const { return event_loops_suspended_; }
void set_event_loops_suspended(bool val) { event_loops_suspended_ = val; } void set_event_loops_suspended(bool val) { event_loops_suspended_ = val; }
static auto CurrentThreadName() -> std::string;
private: private:
explicit CoreFeatureSet(CoreConfig config); explicit CoreFeatureSet(CoreConfig config);
@ -204,6 +209,8 @@ class CoreFeatureSet {
std::optional<std::string> ba_env_user_python_dir_; std::optional<std::string> ba_env_user_python_dir_;
std::optional<std::string> ba_env_site_python_dir_; std::optional<std::string> ba_env_site_python_dir_;
std::string ba_env_data_dir_; std::string ba_env_data_dir_;
std::mutex thread_info_map_mutex_;
std::unordered_map<std::thread::id, std::string> thread_info_map_;
}; };
} // namespace ballistica::core } // namespace ballistica::core

View File

@ -466,7 +466,7 @@ auto CorePlatformApple::CanShowBlockingFatalErrorDialog() -> bool {
if (g_buildconfig.xcode_build() && g_buildconfig.ostype_macos()) { if (g_buildconfig.xcode_build() && g_buildconfig.ostype_macos()) {
return true; return true;
} }
return false; return CorePlatform::CanShowBlockingFatalErrorDialog();
} }
void CorePlatformApple::BlockingFatalErrorDialog(const std::string& message) { void CorePlatformApple::BlockingFatalErrorDialog(const std::string& message) {

View File

@ -826,11 +826,9 @@ auto CorePlatform::MacMusicAppGetPlaylists() -> std::list<std::string> {
} }
void CorePlatform::SetCurrentThreadName(const std::string& name) { void CorePlatform::SetCurrentThreadName(const std::string& name) {
// Currently we leave the main thread alone, otherwise we show up as // We should never be doing this for the main thread.
// "BallisticaMainThread" under "top" on linux (should check other platforms). BA_PRECONDITION_FATAL(!g_core->InMainThread());
if (g_core->InMainThread()) {
return;
}
#if BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS #if BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS
pthread_setname_np(name.c_str()); pthread_setname_np(name.c_str());
#elif BA_OSTYPE_LINUX || BA_OSTYPE_ANDROID #elif BA_OSTYPE_LINUX || BA_OSTYPE_ANDROID

View File

@ -18,7 +18,7 @@ auto ConnectionToHostUDP::SwitchProtocol() -> bool {
// Need a new request id so we ignore further responses to our previous // Need a new request id so we ignore further responses to our previous
// requests. // requests.
GetRequestID(); GetRequestID_();
return true; return true;
} }
return false; return false;
@ -32,7 +32,7 @@ ConnectionToHostUDP::ConnectionToHostUDP(const SockAddr& addr)
did_die_(false), did_die_(false),
last_host_response_time_millisecs_( last_host_response_time_millisecs_(
static_cast<millisecs_t>(g_base->logic->display_time() * 1000.0)) { static_cast<millisecs_t>(g_base->logic->display_time() * 1000.0)) {
GetRequestID(); GetRequestID_();
if (auto* appmode = SceneV1AppMode::GetActiveOrWarn()) { if (auto* appmode = SceneV1AppMode::GetActiveOrWarn()) {
if (appmode->connections()->GetPrintUDPConnectProgress()) { if (appmode->connections()->GetPrintUDPConnectProgress()) {
ScreenMessage(g_base->assets->GetResourceString("connectingToPartyText")); ScreenMessage(g_base->assets->GetResourceString("connectingToPartyText"));
@ -46,11 +46,11 @@ ConnectionToHostUDP::~ConnectionToHostUDP() {
set_connection_dying(true); set_connection_dying(true);
} }
void ConnectionToHostUDP::GetRequestID() { void ConnectionToHostUDP::GetRequestID_() {
// We store a unique-ish request ID to minimize the chance that data for // We store a unique-ish request ID to minimize the chance that data for
// previous connections/etc will muck with us. // previous connections/etc will muck with us. Try to start this value at
// Try to start this value at something that won't be common in packets to // something that won't be common in packets to minimize chance of garbage
// minimize chance of garbage packets causing trouble. // packets causing trouble.
static auto next_request_id = static auto next_request_id =
static_cast<uint8_t>(71 + (rand() % 151)); // NOLINT static_cast<uint8_t>(71 + (rand() % 151)); // NOLINT
request_id_ = next_request_id++; request_id_ = next_request_id++;
@ -95,13 +95,14 @@ void ConnectionToHostUDP::Update() {
{1, 0, 0}); {1, 0, 0});
} }
// Die immediately in this case; no use trying to wait for a disconnect-ack // Die immediately in this case; no use trying to wait for a
// since we've already given up hope of hearing from them. // disconnect-ack since we've already given up hope of hearing from
// them.
Die(); Die();
return; return;
} else if (errored()) { } else if (errored()) {
// If we've errored, keep sending disconnect-requests periodically. // If we've errored, keep sending disconnect-requests periodically. Once
// Once we get a response (or time out in the above code) we'll die. // we get a response (or time out in the above code) we'll die.
if (current_time_millisecs - last_disconnect_request_time_ > 1000) { if (current_time_millisecs - last_disconnect_request_time_ > 1000) {
last_disconnect_request_time_ = current_time_millisecs; last_disconnect_request_time_ = current_time_millisecs;
@ -189,8 +190,8 @@ void ConnectionToHostUDP::Error(const std::string& msg) {
auto ConnectionToHostUDP::GetAsUDP() -> ConnectionToHostUDP* { return this; } auto ConnectionToHostUDP::GetAsUDP() -> ConnectionToHostUDP* { return this; }
void ConnectionToHostUDP::RequestDisconnect() { void ConnectionToHostUDP::RequestDisconnect() {
// Mark us as errored so all future communication results in more disconnect // Mark us as errored so all future communication results in more
// requests. // disconnect requests.
set_errored(true); set_errored(true);
if (client_id_ != -1) { if (client_id_ != -1) {
SendDisconnectRequest(); SendDisconnectRequest();

View File

@ -23,8 +23,8 @@ class ConnectionToHostUDP : public ConnectionToHost {
void set_client_id(int val) { client_id_ = val; } void set_client_id(int val) { client_id_ = val; }
auto client_id() const -> int { return client_id_; } auto client_id() const -> int { return client_id_; }
// Attempt connecting via a different protocol. If none are left to try, /// Attempt connecting via a different protocol. If none are left to try,
// returns false. /// returns false.
auto SwitchProtocol() -> bool; auto SwitchProtocol() -> bool;
void RequestDisconnect() override; void RequestDisconnect() override;
@ -32,16 +32,18 @@ class ConnectionToHostUDP : public ConnectionToHost {
void Error(const std::string& error_msg) override; void Error(const std::string& error_msg) override;
void Die(); void Die();
void SendDisconnectRequest(); void SendDisconnectRequest();
const auto& addr() const { return *addr_; }
private: private:
void GetRequestID(); void GetRequestID_();
uint8_t request_id_{};
std::unique_ptr<SockAddr> addr_;
bool did_die_{}; bool did_die_{};
uint8_t request_id_{};
int client_id_{};
millisecs_t last_client_id_request_time_{}; millisecs_t last_client_id_request_time_{};
millisecs_t last_disconnect_request_time_{}; millisecs_t last_disconnect_request_time_{};
int client_id_{};
millisecs_t last_host_response_time_millisecs_{}; millisecs_t last_host_response_time_millisecs_{};
std::unique_ptr<SockAddr> addr_;
}; };
} // namespace ballistica::scene_v1 } // namespace ballistica::scene_v1

View File

@ -5,13 +5,17 @@
#include "ballistica/base/assets/assets.h" #include "ballistica/base/assets/assets.h"
#include "ballistica/base/networking/network_reader.h" #include "ballistica/base/networking/network_reader.h"
#include "ballistica/base/python/base_python.h" #include "ballistica/base/python/base_python.h"
#include "ballistica/core/python/core_python.h"
#include "ballistica/scene_v1/connection/connection_set.h" #include "ballistica/scene_v1/connection/connection_set.h"
#include "ballistica/scene_v1/connection/connection_to_client.h" #include "ballistica/scene_v1/connection/connection_to_client.h"
#include "ballistica/scene_v1/connection/connection_to_host.h" #include "ballistica/scene_v1/connection/connection_to_host.h"
#include "ballistica/scene_v1/connection/connection_to_host_udp.h"
#include "ballistica/scene_v1/python/scene_v1_python.h"
#include "ballistica/scene_v1/support/scene_v1_app_mode.h" #include "ballistica/scene_v1/support/scene_v1_app_mode.h"
#include "ballistica/shared/math/vector3f.h" #include "ballistica/shared/math/vector3f.h"
#include "ballistica/shared/networking/sockaddr.h" #include "ballistica/shared/networking/sockaddr.h"
#include "ballistica/shared/python/python.h" #include "ballistica/shared/python/python.h"
#include "ballistica/shared/python/python_ref.h"
#include "ballistica/shared/python/python_sys.h" #include "ballistica/shared/python/python_sys.h"
namespace ballistica::scene_v1 { namespace ballistica::scene_v1 {
@ -20,8 +24,7 @@ namespace ballistica::scene_v1 {
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma ide diagnostic ignored "hicpp-signed-bitwise" #pragma ide diagnostic ignored "hicpp-signed-bitwise"
// ------------------------- get_public_party_enabled // ----------------------- get_public_party_enabled ---------------------------
// ---------------------------
static auto PyGetPublicPartyEnabled(PyObject* self, PyObject* args, static auto PyGetPublicPartyEnabled(PyObject* self, PyObject* args,
PyObject* keywds) -> PyObject* { PyObject* keywds) -> PyObject* {
@ -411,7 +414,10 @@ static auto PyGetConnectionToHostInfo(PyObject* self, PyObject* args,
const_cast<char**>(kwlist))) { const_cast<char**>(kwlist))) {
return nullptr; return nullptr;
} }
// Error if we're not in our app-mode. BA_LOG_ONCE(LogLevel::kWarning,
"bascenev1.get_connection_to_host_info() is deprecated; use "
"bascenev1.get_connection_to_host_info_2().");
BA_PRECONDITION(g_base->InLogicThread());
auto* appmode = SceneV1AppMode::GetActiveOrThrow(); auto* appmode = SceneV1AppMode::GetActiveOrThrow();
ConnectionToHost* hc = appmode->connections()->connection_to_host(); ConnectionToHost* hc = appmode->connections()->connection_to_host();
@ -435,6 +441,57 @@ static PyMethodDef PyGetConnectionToHostInfoDef = {
"(internal)", "(internal)",
}; };
// --------------------- get_connection_to_host_info_2 -------------------------
static auto PyGetConnectionToHostInfo2(PyObject* self, PyObject* args,
PyObject* keywds) -> PyObject* {
BA_PYTHON_TRY;
static const char* kwlist[] = {nullptr};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "",
const_cast<char**>(kwlist))) {
return nullptr;
}
BA_PRECONDITION(g_base->InLogicThread());
auto* appmode = SceneV1AppMode::GetActiveOrThrow();
ConnectionToHost* hc = appmode->connections()->connection_to_host();
if (hc) {
PythonRef addr_obj;
PythonRef port_obj;
if (ConnectionToHostUDP* hcu = dynamic_cast<ConnectionToHostUDP*>(hc)) {
addr_obj.Steal(PyUnicode_FromString(hcu->addr().AddressString().c_str()));
port_obj.Steal(PyLong_FromLong(hcu->addr().Port()));
} else {
addr_obj.Acquire(Py_None);
port_obj.Acquire(Py_None);
}
auto args =
g_core->python->objs().Get(core::CorePython::ObjID::kEmptyTuple);
auto keywds = PythonRef::Stolen(Py_BuildValue(
"{sssisOsO}", "name", hc->party_name().c_str(), "build_number",
hc->build_number(), "address", addr_obj.Get(), "port", port_obj.Get()));
auto result = g_scene_v1->python->objs()
.Get(SceneV1Python::ObjID::kHostInfoClass)
.Call(args, keywds);
if (!result.Exists()) {
throw Exception("Failed to instantiate HostInfo.", PyExcType::kRuntime);
}
return result.HandOver();
}
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
static PyMethodDef PyGetConnectionToHostInfo2Def = {
"get_connection_to_host_info_2", // name
(PyCFunction)PyGetConnectionToHostInfo2, // method
METH_VARARGS | METH_KEYWORDS, // flags
"get_connection_to_host_info_2() -> bascenev1.HostInfo | None\n"
"\n"
"Return info about the host we are currently connected to.",
};
// --------------------------- disconnect_from_host ---------------------------- // --------------------------- disconnect_from_host ----------------------------
static auto PyDisconnectFromHost(PyObject* self, PyObject* args, static auto PyDisconnectFromHost(PyObject* self, PyObject* args,
@ -701,6 +758,7 @@ static auto PyChatMessage(PyObject* self, PyObject* args, PyObject* keywds)
&clients_obj, &sender_override_obj)) { &clients_obj, &sender_override_obj)) {
return nullptr; return nullptr;
} }
BA_PRECONDITION(g_base->InLogicThread());
auto* appmode = SceneV1AppMode::GetActiveOrThrow(); auto* appmode = SceneV1AppMode::GetActiveOrThrow();
message = g_base->python->GetPyLString(message_obj); message = g_base->python->GetPyLString(message_obj);
@ -775,6 +833,7 @@ auto PythonMethodsNetworking::GetMethods() -> std::vector<PyMethodDef> {
PyDisconnectClientDef, PyDisconnectClientDef,
PyGetClientPublicDeviceUUIDDef, PyGetClientPublicDeviceUUIDDef,
PyGetConnectionToHostInfoDef, PyGetConnectionToHostInfoDef,
PyGetConnectionToHostInfo2Def,
PyClientInfoQueryResponseDef, PyClientInfoQueryResponseDef,
PyConnectToPartyDef, PyConnectToPartyDef,
PySetAuthenticateClientsDef, PySetAuthenticateClientsDef,

View File

@ -91,6 +91,7 @@ class SceneV1Python {
kGetPlayerIconCall, kGetPlayerIconCall,
kFilterChatMessageCall, kFilterChatMessageCall,
kHandleLocalChatMessageCall, kHandleLocalChatMessageCall,
kHostInfoClass,
kLast // Sentinel; must be at end. kLast // Sentinel; must be at end.
}; };

View File

@ -37,21 +37,16 @@ class ClientSessionNet : public ClientSession {
auto GetBucketNum() -> int; auto GetBucketNum() -> int;
bool writing_replay_{}; bool writing_replay_{};
int delay_sample_counter_{};
float max_delay_smoothed_{};
float last_bucket_max_delay_{};
float current_delay_{};
millisecs_t base_time_received_{}; millisecs_t base_time_received_{};
millisecs_t last_base_time_receive_time_{}; millisecs_t last_base_time_receive_time_{};
millisecs_t leading_base_time_received_{}; millisecs_t leading_base_time_received_{};
millisecs_t leading_base_time_receive_time_{}; millisecs_t leading_base_time_receive_time_{};
Object::WeakRef<ConnectionToHost> connection_to_host_; Object::WeakRef<ConnectionToHost> connection_to_host_;
std::vector<SampleBucket> buckets_{5}; std::vector<SampleBucket> buckets_{5};
// float bucket_max_smoothed_{};
// float bucket_min_smoothed_{};
float max_delay_smoothed_{};
float last_bucket_max_delay_{};
float current_delay_{};
int delay_sample_counter_{};
// int adjust_counter_{};
}; };
} // namespace ballistica::scene_v1 } // namespace ballistica::scene_v1

View File

@ -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 = 21700; const int kEngineBuildNumber = 21707;
const char* kEngineVersion = "1.7.31"; const char* kEngineVersion = "1.7.31";
const int kEngineApiVersion = 8; const int kEngineApiVersion = 8;
@ -290,7 +290,7 @@ void ScreenMessage(const std::string& msg) {
auto CurrentThreadName() -> std::string { auto CurrentThreadName() -> std::string {
// Currently just ask event-loop for this but perhaps should be talking // Currently just ask event-loop for this but perhaps should be talking
// more directly to the OS/etc. to cover more cases. // more directly to the OS/etc. to cover more cases.
return EventLoop::CurrentThreadName(); return core::CoreFeatureSet::CurrentThreadName();
} }
} // namespace ballistica } // namespace ballistica

View File

@ -98,21 +98,6 @@ EventLoop::EventLoop(EventLoopID identifier_in, ThreadSource source)
} }
} }
void EventLoop::SetInternalThreadName_(const std::string& name) {
assert(g_core);
std::scoped_lock lock(g_core->thread_name_map_mutex);
g_core->thread_name_map[std::this_thread::get_id()] = name;
}
void EventLoop::ClearCurrentThreadName() {
assert(g_core);
std::scoped_lock lock(g_core->thread_name_map_mutex);
auto i = g_core->thread_name_map.find(std::this_thread::get_id());
if (i != g_core->thread_name_map.end()) {
g_core->thread_name_map.erase(i);
}
}
// These are all exactly the same; its just a way to try and clarify // These are all exactly the same; its just a way to try and clarify
// in stack traces which thread is running in case it is not otherwise // in stack traces which thread is running in case it is not otherwise
// evident. // evident.
@ -341,53 +326,40 @@ void EventLoop::GetThreadMessages_(std::list<ThreadMessage_>* messages) {
void EventLoop::BootstrapThread_() { void EventLoop::BootstrapThread_() {
assert(!bootstrapped_); assert(!bootstrapped_);
assert(g_core);
thread_id_ = std::this_thread::get_id(); thread_id_ = std::this_thread::get_id();
const char* id_string; const char* id_string;
switch (identifier_) { switch (identifier_) {
case EventLoopID::kLogic: case EventLoopID::kLogic:
name_ = "logic"; name_ = "logic";
id_string = "ballistica logic";
break; break;
case EventLoopID::kStdin: case EventLoopID::kStdin:
name_ = "stdin"; name_ = "stdin";
id_string = "ballistica stdin";
break; break;
case EventLoopID::kAssets: case EventLoopID::kAssets:
name_ = "assets"; name_ = "assets";
id_string = "ballistica assets";
break; break;
case EventLoopID::kFileOut: case EventLoopID::kFileOut:
name_ = "fileout"; name_ = "fileout";
id_string = "ballistica file-out";
break; break;
case EventLoopID::kMain: case EventLoopID::kMain:
name_ = "main"; name_ = "main";
id_string = "ballistica main";
break; break;
case EventLoopID::kAudio: case EventLoopID::kAudio:
name_ = "audio"; name_ = "audio";
id_string = "ballistica audio";
break; break;
case EventLoopID::kBGDynamics: case EventLoopID::kBGDynamics:
name_ = "bgdynamics"; name_ = "bgdynamics";
id_string = "ballistica bg-dynamics";
break; break;
case EventLoopID::kNetworkWrite: case EventLoopID::kNetworkWrite:
name_ = "networkwrite"; name_ = "networkwrite";
id_string = "ballistica network-write";
break; break;
default: default:
throw Exception(); throw Exception();
} }
assert(!name_.empty() && id_string); assert(!name_.empty());
SetInternalThreadName_(name_); g_core->RegisterThread(name_);
// Note: we currently don't do this for our main thread because it
// changes the process name we see in top/etc. Should look into that.
if (identifier_ != EventLoopID::kMain) {
g_core->platform->SetCurrentThreadName(id_string);
}
bootstrapped_ = true; bootstrapped_ = true;
} }
@ -410,7 +382,7 @@ auto EventLoop::ThreadMain_() -> int {
RunToCompletion(); RunToCompletion();
ClearCurrentThreadName(); g_core->UnregisterThread();
return 0; return 0;
} catch (const std::exception& e) { } catch (const std::exception& e) {
auto error_msg = std::string("Unhandled exception in ") auto error_msg = std::string("Unhandled exception in ")
@ -622,35 +594,6 @@ void EventLoop::DeleteTimer(int id) {
timers_.DeleteTimer(id); timers_.DeleteTimer(id);
} }
auto EventLoop::CurrentThreadName() -> std::string {
if (g_core == nullptr) {
return "unknown(not-yet-inited)";
}
{
std::scoped_lock lock(g_core->thread_name_map_mutex);
auto i = g_core->thread_name_map.find(std::this_thread::get_id());
if (i != g_core->thread_name_map.end()) {
return i->second;
}
}
// Ask pthread for the thread name if we don't have one.
// FIXME - move this to platform.
#if BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS || BA_OSTYPE_LINUX
std::string name = "unknown (sys-name=";
char buffer[256];
int result = pthread_getname_np(pthread_self(), buffer, sizeof(buffer));
if (result == 0) {
name += std::string("\"") + buffer + "\")";
} else {
name += "<error " + std::to_string(result) + ">";
}
return name;
#else
return "unknown";
#endif
}
void EventLoop::RunPendingRunnables_() { void EventLoop::RunPendingRunnables_() {
// Pull all runnables off the list first (its possible for one of these // Pull all runnables off the list first (its possible for one of these
// runnables to add more) and then process them. // runnables to add more) and then process them.

View File

@ -25,10 +25,6 @@ class EventLoop {
ThreadSource source = ThreadSource::kCreate); ThreadSource source = ThreadSource::kCreate);
virtual ~EventLoop(); virtual ~EventLoop();
void ClearCurrentThreadName();
static auto CurrentThreadName() -> std::string;
static void SetEventLoopsSuspended(bool enable); static void SetEventLoopsSuspended(bool enable);
static auto AreEventLoopsSuspended() -> bool; static auto AreEventLoopsSuspended() -> bool;
@ -113,7 +109,6 @@ class EventLoop {
: type(type), runnable(runnable), completion_flag{completion_flag} {} : type(type), runnable(runnable), completion_flag{completion_flag} {}
}; };
auto CheckPushRunnableSafety_() -> bool; auto CheckPushRunnableSafety_() -> bool;
void SetInternalThreadName_(const std::string& name);
void WaitForNextEvent_(bool single_cycle); void WaitForNextEvent_(bool single_cycle);
void LogThreadMessageTally_( void LogThreadMessageTally_(
std::vector<std::pair<LogLevel, std::string>>* log_entries); std::vector<std::pair<LogLevel, std::string>>* log_entries);

View File

@ -91,12 +91,16 @@ void FatalError::ReportFatalError(const std::string& message,
if (trace) { if (trace) {
std::string tracestr = trace->FormatForDisplay(); std::string tracestr = trace->FormatForDisplay();
if (!tracestr.empty()) { if (!tracestr.empty()) {
logmsg += ("\nCPP-STACK-TRACE-BEGIN:\n" + tracestr logmsg +=
+ "\nCPP-STACK-TRACE-END"); (("\n----------------------- BALLISTICA-NATIVE-STACK-TRACE-BEGIN "
"--------------------\n")
+ tracestr
+ ("\n----------------------- BALLISTICA-NATIVE-STACK-TRACE-END "
"----------------------"));
} }
delete trace; delete trace;
} else { } else {
logmsg += "\n(CPP-STACK-TRACE-UNAVAILABLE)"; logmsg += "\n(BALLISTICA-NATIVE-STACK-TRACE-UNAVAILABLE)";
} }
} }
} }
@ -155,12 +159,10 @@ void FatalError::DoBlockingFatalErrorDialog(const std::string& message) {
bool* startedptr{&started}; bool* startedptr{&started};
bool* finishedptr{&finished}; bool* finishedptr{&finished};
// If our thread is holding the GIL, release it to give the main thread // If our thread is holding the GIL, release it while we spin; otherwise
// a better chance of getting to the point of displaying the fatal // we can wind up in deadlock if the main thread wants it.
// error. Python::ScopedInterpreterLockRelease gil_release;
if (Python::HaveGIL()) {
Python::PermanentlyReleaseGIL();
}
g_base_soft->PushMainThreadRunnable( g_base_soft->PushMainThreadRunnable(
NewLambdaRunnableUnmanaged([message, startedptr, finishedptr] { NewLambdaRunnableUnmanaged([message, startedptr, finishedptr] {
*startedptr = true; *startedptr = true;

View File

@ -14,22 +14,48 @@ SockAddr::SockAddr(const std::string& addr, int port) {
if (result == 1) { if (result == 1) {
auto* a = reinterpret_cast<sockaddr_in*>(&addr_); auto* a = reinterpret_cast<sockaddr_in*>(&addr_);
a->sin_family = AF_INET; a->sin_family = AF_INET;
a->sin_port = htons(port); // NOLINT a->sin_port = htons(port);
a->sin_addr = addr_out; a->sin_addr = addr_out;
return; return;
} else { } else {
struct in6_addr addr6Out {}; struct in6_addr addr6_out {};
result = inet_pton(AF_INET6, addr.c_str(), &addr6Out); result = inet_pton(AF_INET6, addr.c_str(), &addr6_out);
if (result == 1) { if (result == 1) {
auto* a = reinterpret_cast<sockaddr_in6*>(&addr_); auto* a = reinterpret_cast<sockaddr_in6*>(&addr_);
a->sin6_family = AF_INET6; a->sin6_family = AF_INET6;
a->sin6_port = htons(port); // NOLINT a->sin6_port = htons(port);
a->sin6_addr = addr6Out; a->sin6_addr = addr6_out;
return; return;
} }
} }
} }
throw Exception("Invalid address: '" + addr + "'."); throw Exception("Invalid address: '" + addr + "'.", PyExcType::kValue);
}
auto SockAddr::AddressString() const -> std::string {
if (IsV6()) {
char ip_str[INET6_ADDRSTRLEN];
if (inet_ntop(AF_INET6, &(AsSockAddrIn6()->sin6_addr), ip_str,
INET6_ADDRSTRLEN)
== nullptr) {
throw Exception("inet_ntop failed for v6 addr", PyExcType::kValue);
}
return ip_str;
}
char ip_str[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &(AsSockAddrIn()->sin_addr), ip_str, INET_ADDRSTRLEN)
== nullptr) {
throw Exception("inet_ntop failed for v4 addr", PyExcType::kValue);
}
return ip_str;
}
auto SockAddr::Port() const -> int {
if (IsV6()) {
return ntohs(AsSockAddrIn6()->sin6_port);
} else {
return ntohs(AsSockAddrIn()->sin_port);
}
} }
} // namespace ballistica } // namespace ballistica

View File

@ -15,16 +15,33 @@ class SockAddr {
public: public:
SockAddr() { memset(&addr_, 0, sizeof(addr_)); } SockAddr() { memset(&addr_, 0, sizeof(addr_)); }
// Creates from an ipv4 or ipv6 address string; // Creates from an ipv4 or ipv6 address string; throws an exception on
// throws an exception on error. // error.
SockAddr(const std::string& addr, int port); SockAddr(const std::string& addr, int port);
explicit SockAddr(const sockaddr_storage& addr_in) { explicit SockAddr(const sockaddr_storage& addr_in) {
addr_ = addr_in; addr_ = addr_in;
assert(addr_.ss_family == AF_INET || addr_.ss_family == AF_INET6); assert(addr_.ss_family == AF_INET || addr_.ss_family == AF_INET6);
} }
auto GetSockAddr() const -> const sockaddr* {
auto AsSockAddr() const -> const sockaddr* {
return reinterpret_cast<const sockaddr*>(&addr_); return reinterpret_cast<const sockaddr*>(&addr_);
} }
auto AsSockAddrIn() const -> const sockaddr_in* {
assert(!IsV6());
return reinterpret_cast<const sockaddr_in*>(&addr_);
}
auto AsSockAddrIn6() const -> const sockaddr_in6* {
assert(IsV6());
return reinterpret_cast<const sockaddr_in6*>(&addr_);
}
auto AddressString() const -> std::string;
auto Port() const -> int;
auto GetSockAddrLen() const -> socklen_t { auto GetSockAddrLen() const -> socklen_t {
switch (addr_.ss_family) { switch (addr_.ss_family) {
case AF_INET: case AF_INET:
@ -32,9 +49,10 @@ class SockAddr {
case AF_INET6: case AF_INET6:
return sizeof(sockaddr_in6); return sizeof(sockaddr_in6);
default: default:
throw Exception(); throw Exception(PyExcType::kValue);
} }
} }
auto IsV6() const -> bool { auto IsV6() const -> bool {
switch (addr_.ss_family) { switch (addr_.ss_family) {
case AF_INET: case AF_INET:
@ -45,25 +63,22 @@ class SockAddr {
throw Exception(); throw Exception();
} }
} }
auto operator==(const SockAddr& other) const -> bool { auto operator==(const SockAddr& other) const -> bool {
if (addr_.ss_family != other.addr_.ss_family) return false; if (addr_.ss_family != other.addr_.ss_family) return false;
if (addr_.ss_family == AF_INET) { if (addr_.ss_family == AF_INET) {
return (reinterpret_cast<const sockaddr_in&>(addr_).sin_addr.s_addr auto* a1 = AsSockAddrIn();
== reinterpret_cast<const sockaddr_in&>(other.addr_) auto* a2 = other.AsSockAddrIn();
.sin_addr.s_addr) return !memcmp(&(a1->sin_addr), &(a2->sin_addr), sizeof(in_addr))
&& (reinterpret_cast<const sockaddr_in&>(addr_).sin_port && a1->sin_port == a2->sin_port;
== reinterpret_cast<const sockaddr_in&>(other.addr_).sin_port);
} }
if (addr_.ss_family == AF_INET6) { if (addr_.ss_family == AF_INET6) {
return !memcmp(&(reinterpret_cast<const sockaddr_in6&>(addr_).sin6_addr), auto* a1 = AsSockAddrIn6();
&(reinterpret_cast<const sockaddr_in6&>(other.addr_) auto* a2 = other.AsSockAddrIn6();
.sin6_addr), return !memcmp(&(a1->sin6_addr), &(a2->sin6_addr), sizeof(in6_addr))
sizeof(in6_addr)) && a1->sin6_port == a2->sin6_port;
&& (reinterpret_cast<const sockaddr_in6&>(addr_).sin6_port
== reinterpret_cast<const sockaddr_in6&>(other.addr_)
.sin6_port);
} }
throw Exception(); throw Exception(PyExcType::kValue);
} }
private: private:

View File

@ -416,9 +416,7 @@ class Python::ScopedInterpreterLock::Impl {
}; };
Python::ScopedInterpreterLock::ScopedInterpreterLock() Python::ScopedInterpreterLock::ScopedInterpreterLock()
: impl_{new Python::ScopedInterpreterLock::Impl()} : impl_{new Python::ScopedInterpreterLock::Impl()} {}
// impl_{std::make_unique<Python::ScopedInterpreterLock::Impl>()}
{}
Python::ScopedInterpreterLock::~ScopedInterpreterLock() { delete impl_; } Python::ScopedInterpreterLock::~ScopedInterpreterLock() { delete impl_; }

View File

@ -41,7 +41,8 @@ class Python {
/// Use this to protect Python code that may be run in cases where we /// Use this to protect Python code that may be run in cases where we
/// don't hold the Global Interpreter Lock (GIL). (Basically anything /// don't hold the Global Interpreter Lock (GIL). (Basically anything
/// outside of the logic thread). /// outside of the logic thread). This will release and then restore
/// the GIL if it is held initially; otherwise it is a no-op.
class ScopedInterpreterLock { class ScopedInterpreterLock {
public: public:
ScopedInterpreterLock(); ScopedInterpreterLock();
@ -49,9 +50,6 @@ class Python {
private: private:
class Impl; 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_{}; Impl* impl_{};
}; };
@ -64,9 +62,6 @@ class Python {
private: private:
class Impl; 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_{}; Impl* impl_{};
}; };

View File

@ -118,7 +118,9 @@ class PythonRef {
/// Release the held reference (if one is held). /// Release the held reference (if one is held).
void Release(); void Release();
/// Clear the ref without decrementing its count and return the raw PyObject* /// Clear the ref without decrementing its count and return the raw
/// PyObject*. Useful for functions that are expected to return a new
/// Python ref.
auto HandOver() -> PyObject* { auto HandOver() -> PyObject* {
assert(obj_); assert(obj_);
PyObject* obj = obj_; PyObject* obj = obj_;
@ -151,8 +153,9 @@ class PythonRef {
/// Throws Exception if an error occurs. /// Throws Exception if an error occurs.
auto DictGetItem(const char* name) const -> PythonRef; auto DictGetItem(const char* name) const -> PythonRef;
/// The equivalent of calling Python str() on the contained PyObject. /// The equivalent of calling Python str() on the contained PyObject, and
/// Gracefully handles invalid refs. /// gracefully handles invalid refs. To throw exceptions on invalid refs,
/// use ValueAsString();
auto Str() const -> std::string; auto Str() const -> std::string;
/// The equivalent of calling repr() on the contained PyObject. /// The equivalent of calling repr() on the contained PyObject.

View File

@ -2589,90 +2589,6 @@ static PyMethodDef PyGetSpecialWidgetDef = {
"(internal)", "(internal)",
}; };
// -------------------------- have_incentivized_ad -----------------------------
// returns an extra hash value that can be incorporated into security checks;
// this contains things like whether console commands have been run, etc.
static auto PyHaveIncentivizedAd(PyObject* self, PyObject* args,
PyObject* keywds) -> PyObject* {
BA_PYTHON_TRY;
static const char* kwlist[] = {nullptr};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "",
const_cast<char**>(kwlist))) {
return nullptr;
}
if (g_core->have_incentivized_ad) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
BA_PYTHON_CATCH;
}
static PyMethodDef PyHaveIncentivizedAdDef = {
"have_incentivized_ad", // name
(PyCFunction)PyHaveIncentivizedAd, // method
METH_VARARGS | METH_KEYWORDS, // flags
"have_incentivized_ad() -> bool\n"
"\n"
"(internal)",
};
// ----------------------------- can_show_ad -----------------------------------
// this returns whether it makes sense to show an currently
static auto PyCanShowAd(PyObject* self, PyObject* args, PyObject* keywds)
-> PyObject* {
BA_PYTHON_TRY;
BA_PRECONDITION(g_base->InLogicThread());
// if we've got any network connections, no ads.
// (don't want to make someone on the other end wait or risk disconnecting
// them or whatnot). Also disallow ads if remote apps are connected; at least
// on Android, ads pause our activity which disconnects the remote app.
// (need to fix this).
if (g_base->app_mode()->HasConnectionToHost()
|| g_base->app_mode()->HasConnectionToClients()
|| g_base->input->HaveRemoteAppController()) {
Py_RETURN_FALSE;
}
Py_RETURN_TRUE; // all systems go..
BA_PYTHON_CATCH;
}
static PyMethodDef PyCanShowAdDef = {
"can_show_ad", // name
(PyCFunction)PyCanShowAd, // method
METH_VARARGS | METH_KEYWORDS, // flags
"can_show_ad() -> bool\n"
"\n"
"(internal)",
};
// ---------------------------- has_video_ads ----------------------------------
static auto PyHasVideoAds(PyObject* self, PyObject* args, PyObject* keywds)
-> PyObject* {
BA_PYTHON_TRY;
if (g_core->platform->GetHasVideoAds()) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
BA_PYTHON_CATCH;
}
static PyMethodDef PyHasVideoAdsDef = {
"has_video_ads", // name
(PyCFunction)PyHasVideoAds, // method
METH_VARARGS | METH_KEYWORDS, // flags
"has_video_ads() -> bool\n"
"\n"
"(internal)",
};
// ------------------------------ back_press ----------------------------------- // ------------------------------ back_press -----------------------------------
static auto PyBackPress(PyObject* self, PyObject* args, PyObject* keywds) static auto PyBackPress(PyObject* self, PyObject* args, PyObject* keywds)
@ -2893,9 +2809,6 @@ auto PythonMethodsUIV1::GetMethods() -> std::vector<PyMethodDef> {
PyOpenFileExternallyDef, PyOpenFileExternallyDef,
PyOpenURLDef, PyOpenURLDef,
PyBackPressDef, PyBackPressDef,
PyHasVideoAdsDef,
PyCanShowAdDef,
PyHaveIncentivizedAdDef,
PyGetSpecialWidgetDef, PyGetSpecialWidgetDef,
PySetPartyWindowOpenDef, PySetPartyWindowOpenDef,
PySetPartyIconAlwaysVisibleDef, PySetPartyIconAlwaysVisibleDef,

View File

@ -10,6 +10,7 @@ from bascenev1._player import Player
from bascenev1._dependency import AssetPackage from bascenev1._dependency import AssetPackage
from bascenev1._activity import Activity from bascenev1._activity import Activity
from bascenev1._session import Session from bascenev1._session import Session
from bascenev1._net import HostInfo
import _bascenev1 import _bascenev1
# The C++ layer looks for this variable: # The C++ layer looks for this variable:
@ -30,4 +31,5 @@ values = [
AssetPackage, # kAssetPackageClass AssetPackage, # kAssetPackageClass
Activity, # kActivityClass Activity, # kActivityClass
Session, # kSceneV1SessionClass Session, # kSceneV1SessionClass
HostInfo, # kHostInfoClass
] ]

View File

@ -5,22 +5,49 @@
from __future__ import annotations from __future__ import annotations
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING from dataclasses import dataclass
from typing import TYPE_CHECKING, Annotated
from efro.dataclassio import ioprepped, IOAttrs
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
class AppExperience(Enum): class AppInterfaceIdiom(Enum):
"""Overall experience that can be provided by a Ballistica app. """A general form-factor or way of experiencing a Ballistica app.
This corresponds generally, but not exactly, to distinct apps built Note that it is possible for a running app to switch idioms (for
with Ballistica. However, a single app may support multiple experiences, instance if a mobile device or computer is connected to a TV).
or there may be multiple apps targeting one experience. Cloud components
such as leagues are generally associated with an AppExperience.
""" """
# A special experience category that is supported everywhere. Used PHONE = 'phone'
TABLET = 'tablet'
DESKTOP = 'desktop'
TV = 'tv'
XR = 'xr'
class AppExperience(Enum):
"""A particular experience that can be provided by a Ballistica app.
This is one metric used to isolate different playerbases from
eachother where there might be no technical barriers doing so.
For example, a casual one-hand-playable phone game and an augmented
reality tabletop game may both use the same scene-versions and
networking-protocols and whatnot, but it would make no sense to
allow players of one join servers for the other. AppExperience can
be used to keep these player bases separate.
Generally a single Ballistica app targets a single AppExperience.
This is not a technical requirement, however. A single app may
support multiple experiences, or there may be multiple apps
targeting one experience. Cloud components such as leagues are
generally associated with an AppExperience so that they are only
visible to client apps designed for that play style.
"""
# An experience that is supported everywhere. Used
# for the default empty AppMode when starting the app, etc. # for the default empty AppMode when starting the app, etc.
EMPTY = 'empty' EMPTY = 'empty'
@ -33,3 +60,79 @@ class AppExperience(Enum):
# touch-screen allowing a mobile device to be used as a game # touch-screen allowing a mobile device to be used as a game
# controller. # controller.
REMOTE = 'remote' REMOTE = 'remote'
class AppArchitecture(Enum):
"""Processor architecture the App is running on."""
ARM = 'arm'
ARM64 = 'arm64'
X86 = 'x86'
X86_64 = 'x86_64'
class AppPlatform(Enum):
"""Overall platform a Ballistica build can be targeting.
Each distinct flavor of an app has a unique combination
of AppPlatform and AppVariant. Generally platform describes
a set of hardware, while variant describes a destination or
purpose for the build.
"""
MAC = 'mac'
WINDOWS = 'windows'
LINUX = 'linux'
ANDROID = 'android'
IOS = 'ios'
TVOS = 'tvos'
class AppVariant(Enum):
"""A unique Ballistica build type within a single platform.
Each distinct flavor of an app has a unique combination
of AppPlatform and AppVariant. Generally platform describes
a set of hardware, while variant describes a destination or
purpose for the build.
"""
# Default builds.
GENERIC = 'generic'
# Builds intended for public testing (may have some extra checks
# or logging enabled).
TEST = 'test'
# Various stores.
AMAZON_APPSTORE = 'amazon_appstore'
GOOGLE_PLAY = 'google_play'
APP_STORE = 'app_store'
WINDOWS_STORE = 'windows_store'
STEAM = 'steam'
META = 'meta'
EPIC_GAMES_STORE = 'epic_games_store'
# Other.
ARCADE = 'arcade'
DEMO = 'demo'
@ioprepped
@dataclass
class AppInstanceInfo:
"""General info about an individual running app."""
name = Annotated[str, IOAttrs('n')]
version = Annotated[str, IOAttrs('v')]
build = Annotated[int, IOAttrs('b')]
platform = Annotated[AppPlatform, IOAttrs('p')]
variant = Annotated[AppVariant, IOAttrs('va')]
architecture = Annotated[AppArchitecture, IOAttrs('a')]
os_version = Annotated[str | None, IOAttrs('o')]
interface_idiom: Annotated[AppInterfaceIdiom, IOAttrs('i')]
locale: Annotated[str, IOAttrs('l')]
device: Annotated[str | None, IOAttrs('d')]

View File

@ -216,6 +216,12 @@ def _writefuncs(
'import bascenev1 # pylint: disable=cyclic-import\n' 'import bascenev1 # pylint: disable=cyclic-import\n'
'return bascenev1.Time(0.0)' 'return bascenev1.Time(0.0)'
) )
elif returns == 'bascenev1.HostInfo | None':
returnstr = (
'import bascenev1 # pylint: disable=cyclic-import\n'
'return bascenev1.HostInfo(\'dummyname\', -1,'
' \'dummy_addr\', -1)'
)
elif returns == 'babase.DisplayTime': elif returns == 'babase.DisplayTime':
returnstr = ( returnstr = (
'import babase # pylint: disable=cyclic-import\n' 'import babase # pylint: disable=cyclic-import\n'

View File

@ -426,7 +426,6 @@ class ProjectUpdater:
# from batools.xcode import update_xcode_project # from batools.xcode import update_xcode_project
for projpath in [ for projpath in [
# 'ballisticakit-mac.xcodeproj/project.pbxproj',
# 'ballisticakit-ios.xcodeproj/project.pbxproj', # 'ballisticakit-ios.xcodeproj/project.pbxproj',
'ballisticakit-xcode/BallisticaKit.xcodeproj/project.pbxproj', 'ballisticakit-xcode/BallisticaKit.xcodeproj/project.pbxproj',
]: ]:

View File

@ -62,7 +62,7 @@ def build_openal(arch: str, mode: str) -> None:
) )
# subprocess.run(['git', 'checkout', '1.23.1'], check=True, cwd=builddir) # subprocess.run(['git', 'checkout', '1.23.1'], check=True, cwd=builddir)
subprocess.run( subprocess.run(
['git', 'checkout', '5b5b948516f7340810ebbfdd5e46eb40f85d2e56'], ['git', 'checkout', 'b81a270f6c1e795ca70d7684e0ccf35a19f247e2'],
check=True, check=True,
cwd=builddir, cwd=builddir,
) )