diff --git a/.efrocachemap b/.efrocachemap index 3dcc07ae..4d5f5d4d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -421,7 +421,7 @@ "build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26", "build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8", "build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55", - "build/assets/ba_data/data/langdata.json": "b2fbc1751bd168470392de5370c196f4", + "build/assets/ba_data/data/langdata.json": "0b15d171ebcc56d324875b48436b58c2", "build/assets/ba_data/data/languages/arabic.json": "c21378ee214a9dd0cb2971cd46b74374", "build/assets/ba_data/data/languages/belarussian.json": "4d89ed5f9c615771d4fa2bb1834942d3", "build/assets/ba_data/data/languages/chinese.json": "0a9d9534e7329d1e886adae6fdc007c4", @@ -440,7 +440,7 @@ "build/assets/ba_data/data/languages/hindi.json": "8ea0c58a44a24edb131d0e53b074d1f6", "build/assets/ba_data/data/languages/hungarian.json": "796a290a8c44a1e7635208c2ff5fdc6e", "build/assets/ba_data/data/languages/indonesian.json": "d7f1cafecad05e0dcd34345e0088c4de", - "build/assets/ba_data/data/languages/italian.json": "b998195a8c5e745dca953ca54745a5f6", + "build/assets/ba_data/data/languages/italian.json": "e4acd4e58ef8db78f3369bf881f84c55", "build/assets/ba_data/data/languages/korean.json": "ca1122a9ee551da3f75ae632012bd0e2", "build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38", "build/assets/ba_data/data/languages/persian.json": "4585070bd509600019ec8dc3bb47bfb8", @@ -454,7 +454,7 @@ "build/assets/ba_data/data/languages/swedish.json": "77d671f10613291ebf9c71da66f18a18", "build/assets/ba_data/data/languages/tamil.json": "65ab7798d637fa62a703750179eeb723", "build/assets/ba_data/data/languages/thai.json": "33f63753c9af9a5b238d229a0bf23fbc", - "build/assets/ba_data/data/languages/turkish.json": "776d1a0c9ef2333a9110d93558ab19e2", + "build/assets/ba_data/data/languages/turkish.json": "71fd6c59650c03164a94d884bc7e5263", "build/assets/ba_data/data/languages/ukrainian.json": "f72eb51abfbbb56e27866895d7e947d2", "build/assets/ba_data/data/languages/venetian.json": "9fe1a58d9e5dfb00f31ce3b2eb9993f4", "build/assets/ba_data/data/languages/vietnamese.json": "921cd1e50f60fe3e101f246e172750ba", @@ -4056,50 +4056,50 @@ "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "d81b7738fc395f6f926aabaee1920925", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "70d7de73a945afbe78f6ba94dd0fd78c", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "5ee9cf8e99fb9fbc6b80ef7fa6840be5", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "8eb65d8768f338c7188de404d584068f", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "4422950377f4194463b38533487b81df", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "3e85a676808245e0a279e2fb28fad8fc", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "50ac87225e3b4ac843d83fcec96ef542", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "ce8fedb78aac2ec288697fbace511d68", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "9db6948f77ff98d109e799d4d97266f7", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "517b1d6326879fd7ae1ad17d96e7c9ee", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "b49b73a09460467bba983c301d33feb8", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "7b4741075224986c1776bc9e538b80cc", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "f8a1e3030d6e9129f95ab5b7ea171134", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "615505f555b1ecf567ac00c1a71d4073", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "257f4ec71878b30f0a3619d8a5a278d8", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "0d4a6355de77872b17b4ed2856cfd3e3", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "e76d8896417d7c468b743f865f6d317a", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "1f7b66a5c7bf998f9d59fa28ef1a2dc5", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "a537bc369c09da6384a47e878b7dd11d", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "0b34b2bdfc77cb1f8c3968c16b304307", - "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "844bab8bf2324a35e4f71510fb4065f3", - "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "0320ab824c7b9271dfdd6361dcd51d82", - "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "844bab8bf2324a35e4f71510fb4065f3", - "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "0320ab824c7b9271dfdd6361dcd51d82", - "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "28ec03fb21247269ea16b7dc31cc37c9", - "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "80e61c0f2a2e665eaa6260b60ca92144", - "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "28ec03fb21247269ea16b7dc31cc37c9", - "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "80e61c0f2a2e665eaa6260b60ca92144", - "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "773c691b680d407f050d11a0814048cd", - "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "22158f39a92f54838ca05f38e7f635a9", - "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "773c691b680d407f050d11a0814048cd", - "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "22158f39a92f54838ca05f38e7f635a9", - "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "8d88b975df7ccff1af919ea738dcbc0f", - "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "f7de016cce83b57002b87f42575c2287", - "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "054de6792232f57d2ad4a5a81e5b7e5f", - "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "f7de016cce83b57002b87f42575c2287", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "7f38979e847d5b3abef78acf83e41334", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "10ebbf27705f024b696c92db94d75506", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "287f846d6d424639348a02030f2bace9", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "0a2987deb121f5eb044c220079c17d50", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "97b59f0376cc0bff65bc8f583127e62b", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "c7421859bac7d02acb487784573cffd9", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "8e70dcb1e9c6a046473d2fec13796b76", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "104baba8083e75102f81c6e1c6b552b5", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "ad6316e04f09de546d25171512f783b2", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "19495e4313121d5574ab69efcbbcedd7", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "d8f215de52d492ce1790d9e1714b4cec", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "b057d6d9627c7400496080c48dd344cd", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "1bd60c4476b7471364be2534d3cb8185", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "011bceb35c7f53b98f2ab79798409679", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "0055dfac758acdeb5a39e436da5d71be", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "2daa69d1df9927e6fc17b0aabd5c62f6", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "2159ce4b648b1172e3d2f349e61f2b1b", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "26163f755e45586da35c1ed6499c0416", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "410c70d8d833458616a0056972e558c4", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "6e4473952a022e30340b6decae9da58a", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "0c63291b5842dafcfae558ef3c36d35a", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "7195da4e4abae862f41c28764b35662b", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "5a6ad8a9f0d5cd964661df32ac4efb47", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "376059ea5f812ace7629ad29a8d77a9a", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "7a0c87d9e673b28157845f71ff957df6", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "3603019e3dbf055c37f5fabbe9538c48", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "14f6e17cc5698341ed5607834107e608", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "679703f9ec7c6f9c0708c9b13c9c6c06", + "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "e4952c83427611c5a66a864d8bb3bc4f", + "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "55df380ad6f3b38094bc82f6bb2a34bb", + "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "e4952c83427611c5a66a864d8bb3bc4f", + "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "55df380ad6f3b38094bc82f6bb2a34bb", + "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "f37c917e8336be6afe86842fc0cd1586", + "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "aaf0413c15988e332d27b7fd6eb1ba1f", + "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "f37c917e8336be6afe86842fc0cd1586", + "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "aaf0413c15988e332d27b7fd6eb1ba1f", + "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "f66008360fc266ada358731656dfa91a", + "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "712cd1dda7661826129b8023949ebebe", + "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "f66008360fc266ada358731656dfa91a", + "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "712cd1dda7661826129b8023949ebebe", + "build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "5488eb05a8c45904243ff5cb1fc483cd", + "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "55aef97c30ade6b21e93b7d8a45ae670", + "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "519d0d2895489e5905e65e53384b96ba", + "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "55aef97c30ade6b21e93b7d8a45ae670", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "c9e82195e722512599ec7edcb456c78d", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "18b47849e222dd7b1bef9bd1a07473c9", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "6c44557f5392bb3cd2d9a983add52d0b", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "0bd4099b6b594f62b806c9d74a84095a", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "a36752eee64f76c1868937247aaaee32", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "9ac33f02579ee14e4ad6a0b6b5a82a36", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "87bc0ff42442b60c817805ab07c65769", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "cedd1f2c367b84c20377c282453825f2", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "28323912b56ec07701eda3d41a6a4101", "src/ballistica/base/mgen/pyembed/binding_base.inc": "6df0f34207346d89a72924249ddd4706", diff --git a/CHANGELOG.md b/CHANGELOG.md index a0bab389..ad501f17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.28 (build 21531, api 8, 2023-10-27) +### 1.7.28 (build 21543, api 8, 2023-10-31) - Massively cleaned up code related to rendering and window systems (OpenGL, SDL, etc). This code had been growing into a nasty tangle for 15 years @@ -196,10 +196,10 @@ including things like the internal EventLoop timeline. Please holler if you notice anything running 1000x too fast or slow. In general my strategy going forward is to use microseconds for exact internal time values but to mostly - expose float seconds to the user on the Python layer. There were starting to - be a few cases were integer milliseconds was not enough precision for internal - values. For instance, if we run with unclamped framerates and hit several - hundred FPS, milliseconds per frame would drop to 0 which could cause + expose float seconds to the user, especially on the Python layer. There were + starting to be a few cases were integer milliseconds was not enough precision + for internal values. For instance, if we run with unclamped framerates and hit + several hundred FPS, milliseconds per frame would drop to 0 which caused some problems. Note that scenev1 will be remaining on milliseconds internally for compatibility reasons. Scenev2 should move to microseconds though. diff --git a/ballisticakit-cmake/CMakeLists.txt b/ballisticakit-cmake/CMakeLists.txt index c4d1ed64..12934e4e 100644 --- a/ballisticakit-cmake/CMakeLists.txt +++ b/ballisticakit-cmake/CMakeLists.txt @@ -360,6 +360,8 @@ set(BALLISTICA_SOURCES ${BA_SRC_ROOT}/ballistica/base/graphics/support/net_graph.cc ${BA_SRC_ROOT}/ballistica/base/graphics/support/net_graph.h ${BA_SRC_ROOT}/ballistica/base/graphics/support/render_command_buffer.h + ${BA_SRC_ROOT}/ballistica/base/graphics/support/screen_messages.cc + ${BA_SRC_ROOT}/ballistica/base/graphics/support/screen_messages.h ${BA_SRC_ROOT}/ballistica/base/graphics/text/font_page_map_data.h ${BA_SRC_ROOT}/ballistica/base/graphics/text/text_graphics.cc ${BA_SRC_ROOT}/ballistica/base/graphics/text/text_graphics.h @@ -449,8 +451,6 @@ set(BALLISTICA_SOURCES ${BA_SRC_ROOT}/ballistica/base/support/repeater.h ${BA_SRC_ROOT}/ballistica/base/support/stdio_console.cc ${BA_SRC_ROOT}/ballistica/base/support/stdio_console.h - ${BA_SRC_ROOT}/ballistica/base/support/stress_test.cc - ${BA_SRC_ROOT}/ballistica/base/support/stress_test.h ${BA_SRC_ROOT}/ballistica/base/ui/dev_console.cc ${BA_SRC_ROOT}/ballistica/base/ui/dev_console.h ${BA_SRC_ROOT}/ballistica/base/ui/ui.cc @@ -463,6 +463,8 @@ set(BALLISTICA_SOURCES ${BA_SRC_ROOT}/ballistica/classic/python/classic_python.h ${BA_SRC_ROOT}/ballistica/classic/python/methods/python_methods_classic.cc ${BA_SRC_ROOT}/ballistica/classic/python/methods/python_methods_classic.h + ${BA_SRC_ROOT}/ballistica/classic/support/stress_test.cc + ${BA_SRC_ROOT}/ballistica/classic/support/stress_test.h ${BA_SRC_ROOT}/ballistica/classic/support/v1_account.cc ${BA_SRC_ROOT}/ballistica/classic/support/v1_account.h ${BA_SRC_ROOT}/ballistica/core/core.cc diff --git a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj index fc194878..ff64f440 100644 --- a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj +++ b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj @@ -352,6 +352,8 @@ + + @@ -441,8 +443,6 @@ - - @@ -455,6 +455,8 @@ + + diff --git a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters index 078cbd38..441851e6 100644 --- a/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters +++ b/ballisticakit-windows/Generic/BallisticaKitGeneric.vcxproj.filters @@ -490,6 +490,12 @@ ballistica\base\graphics\support + + ballistica\base\graphics\support + + + ballistica\base\graphics\support + ballistica\base\graphics\text @@ -757,12 +763,6 @@ ballistica\base\support - - ballistica\base\support - - - ballistica\base\support - ballistica\base\ui @@ -799,6 +799,12 @@ ballistica\classic\python\methods + + ballistica\classic\support + + + ballistica\classic\support + ballistica\classic\support diff --git a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj index b4f73ad3..c3b0779c 100644 --- a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj +++ b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj @@ -347,6 +347,8 @@ + + @@ -436,8 +438,6 @@ - - @@ -450,6 +450,8 @@ + + diff --git a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters index 078cbd38..441851e6 100644 --- a/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters +++ b/ballisticakit-windows/Headless/BallisticaKitHeadless.vcxproj.filters @@ -490,6 +490,12 @@ ballistica\base\graphics\support + + ballistica\base\graphics\support + + + ballistica\base\graphics\support + ballistica\base\graphics\text @@ -757,12 +763,6 @@ ballistica\base\support - - ballistica\base\support - - - ballistica\base\support - ballistica\base\ui @@ -799,6 +799,12 @@ ballistica\classic\python\methods + + ballistica\classic\support + + + ballistica\classic\support + ballistica\classic\support diff --git a/config/projectconfig.json b/config/projectconfig.json index 6dbb5ae0..68dd6d90 100644 --- a/config/projectconfig.json +++ b/config/projectconfig.json @@ -10,7 +10,8 @@ "src/ballistica/base/graphics/texture/ktx.cc", "src/ballistica/core/platform/android/android_gl3.h", "src/ballistica/base/platform/apple/app_delegate.h", - "src/ballistica/base/platform/apple/scripting_bridge_music.h", + "src/ballistica/base/platform/apple/MacMusicApp.h", + "src/ballistica/base/platform/apple/MacMusicAppScriptingBridge.h", "src/ballistica/core/platform/android/utf8/checked.h", "src/ballistica/core/platform/android/utf8/unchecked.h", "src/ballistica/core/platform/android/utf8/core.h", diff --git a/src/assets/ba_data/python/babase/__init__.py b/src/assets/ba_data/python/babase/__init__.py index 9eb09af0..e15a774a 100644 --- a/src/assets/ba_data/python/babase/__init__.py +++ b/src/assets/ba_data/python/babase/__init__.py @@ -85,7 +85,6 @@ from _babase import ( screenmessage, set_analytics_screen, set_low_level_config_value, - set_stress_testing, set_thread_name, set_ui_input_device, show_progress_bar, @@ -303,7 +302,6 @@ __all__ = [ 'SessionTeamNotFoundError', 'set_analytics_screen', 'set_low_level_config_value', - 'set_stress_testing', 'set_thread_name', 'set_ui_input_device', 'show_progress_bar', diff --git a/src/assets/ba_data/python/baclassic/_benchmark.py b/src/assets/ba_data/python/baclassic/_benchmark.py index 18e04335..6bb22743 100644 --- a/src/assets/ba_data/python/baclassic/_benchmark.py +++ b/src/assets/ba_data/python/baclassic/_benchmark.py @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING import babase import bascenev1 +import _baclassic if TYPE_CHECKING: from typing import Any, Sequence @@ -84,7 +85,8 @@ def run_stress_test( def stop_stress_test() -> None: """End a running stress test.""" - babase.set_stress_testing(False, 0) + + _baclassic.set_stress_testing(False, 0) assert babase.app.classic is not None try: if babase.app.classic.stress_test_reset_timer is not None: @@ -134,14 +136,14 @@ def start_stress_test(args: dict[str, Any]) -> None: babase.Call(bascenev1.new_host_session, FreeForAllSession), ), ) - babase.set_stress_testing(True, args['player_count']) + _baclassic.set_stress_testing(True, args['player_count']) babase.app.classic.stress_test_reset_timer = babase.AppTimer( args['round_duration'], babase.Call(_reset_stress_test, args) ) def _reset_stress_test(args: dict[str, Any]) -> None: - babase.set_stress_testing(False, args['player_count']) + _baclassic.set_stress_testing(False, args['player_count']) babase.screenmessage('Resetting stress test...') session = bascenev1.get_foreground_host_session() assert session is not None diff --git a/src/assets/ba_data/python/baclassic/_music.py b/src/assets/ba_data/python/baclassic/_music.py index bdda3a3a..8f439d79 100644 --- a/src/assets/ba_data/python/baclassic/_music.py +++ b/src/assets/ba_data/python/baclassic/_music.py @@ -165,15 +165,16 @@ class MusicSubsystem: def supports_soundtrack_entry_type(self, entry_type: str) -> bool: """Return whether provided soundtrack entry type is supported here.""" - uas = babase.env()['legacy_user_agent_string'] - assert isinstance(uas, str) - - # FIXME: Generalize this. + # Note to self; can't access babase.app.classic here because + # we are called during its construction. + env = babase.env() + platform = env.get('platform') + assert isinstance(platform, str) if entry_type == 'iTunesPlaylist': - return 'Mac' in uas + return platform == 'mac' and babase.is_xcode_build() if entry_type in ('musicFile', 'musicFolder'): return ( - 'android' in uas + platform == 'android' and babase.android_get_external_files_dir() is not None ) if entry_type == 'default': diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 1d1469c6..f3969a7d 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21531 +TARGET_BALLISTICA_BUILD = 21543 TARGET_BALLISTICA_VERSION = '1.7.28' diff --git a/src/ballistica/base/base.cc b/src/ballistica/base/base.cc index 2871e6ac..00953ffa 100644 --- a/src/ballistica/base/base.cc +++ b/src/ballistica/base/base.cc @@ -9,6 +9,7 @@ #include "ballistica/base/audio/audio_server.h" #include "ballistica/base/dynamics/bg/bg_dynamics_server.h" #include "ballistica/base/graphics/graphics_server.h" +#include "ballistica/base/graphics/support/screen_messages.h" #include "ballistica/base/graphics/text/text_graphics.h" #include "ballistica/base/input/input.h" #include "ballistica/base/logic/logic.h" @@ -20,11 +21,11 @@ #include "ballistica/base/python/class/python_class_feature_set_data.h" #include "ballistica/base/python/support/python_context_call.h" #include "ballistica/base/support/app_config.h" +#include "ballistica/base/support/app_timer.h" #include "ballistica/base/support/base_build_switches.h" #include "ballistica/base/support/huffman.h" #include "ballistica/base/support/plus_soft.h" #include "ballistica/base/support/stdio_console.h" -#include "ballistica/base/support/stress_test.h" #include "ballistica/base/ui/dev_console.h" #include "ballistica/base/ui/ui_delegate.h" #include "ballistica/core/python/core_python.h" @@ -63,7 +64,6 @@ BaseFeatureSet::BaseFeatureSet() python{new BasePython()}, stdio_console{g_buildconfig.enable_stdio_console() ? new StdioConsole() : nullptr}, - stress_test_{new StressTest()}, text_graphics{new TextGraphics()}, ui{new UI()}, utils{new Utils()} { @@ -465,8 +465,9 @@ auto BaseFeatureSet::InGraphicsContext() const -> bool { void BaseFeatureSet::ScreenMessage(const std::string& s, const Vector3f& color) { - logic->event_loop()->PushCall( - [this, s, color] { graphics->AddScreenMessage(s, color); }); + logic->event_loop()->PushCall([this, s, color] { + graphics->screenmessages->AddScreenMessage(s, color); + }); } void BaseFeatureSet::DoV1CloudLog(const std::string& msg) { diff --git a/src/ballistica/base/base.h b/src/ballistica/base/base.h index f4b04101..2503a134 100644 --- a/src/ballistica/base/base.h +++ b/src/ballistica/base/base.h @@ -102,12 +102,12 @@ class RemoteAppServer; class RemoteControlInput; class Repeater; class ScoreToBeat; +class ScreenMessages; class AppAdapterSDL; class SDLContext; class SoundAsset; class SpriteMesh; class StdioConsole; -class StressTest; class Module; class TestInput; class TextGroup; @@ -752,8 +752,6 @@ class BaseFeatureSet : public FeatureSetNativeComponent, void set_app_mode(AppMode* mode); auto* app_mode() const { return app_mode_; } - auto* stress_test() const { return stress_test_; } - /// Whether we're running under ballisticakit_server.py /// (affects some app behavior). auto server_wrapper_managed() { return server_wrapper_managed_; } @@ -776,7 +774,6 @@ class BaseFeatureSet : public FeatureSetNativeComponent, AppMode* app_mode_; PlusSoftInterface* plus_soft_{}; ClassicSoftInterface* classic_soft_{}; - StressTest* stress_test_; std::mutex shutdown_suppress_lock_; bool shutdown_suppress_disallowed_{}; diff --git a/src/ballistica/base/graphics/graphics.cc b/src/ballistica/base/graphics/graphics.cc index 790f955d..7fe3f3e9 100644 --- a/src/ballistica/base/graphics/graphics.cc +++ b/src/ballistica/base/graphics/graphics.cc @@ -11,25 +11,23 @@ #include "ballistica/base/graphics/component/special_component.h" #include "ballistica/base/graphics/component/sprite_component.h" #include "ballistica/base/graphics/graphics_server.h" -#include "ballistica/base/graphics/mesh/nine_patch_mesh.h" #include "ballistica/base/graphics/support/camera.h" #include "ballistica/base/graphics/support/net_graph.h" -#include "ballistica/base/graphics/text/text_graphics.h" +#include "ballistica/base/graphics/support/screen_messages.h" #include "ballistica/base/input/input.h" #include "ballistica/base/logic/logic.h" #include "ballistica/base/python/support/python_context_call.h" #include "ballistica/base/support/app_config.h" #include "ballistica/base/ui/ui.h" #include "ballistica/shared/foundation/event_loop.h" -#include "ballistica/shared/generic/utils.h" namespace ballistica::base { -const float kScreenMessageZDepth{-0.06f}; -const float kScreenMeshZDepth{-0.05f}; +const float kScreenTextZDepth{-0.06f}; const float kProgressBarZDepth{0.0f}; const int kProgressBarFadeTime{500}; const float kDebugImgZDepth{-0.04f}; +const float kScreenMeshZDepth{-0.05f}; auto Graphics::IsShaderTransparent(ShadingType c) -> bool { switch (c) { @@ -80,7 +78,7 @@ auto Graphics::IsShaderTransparent(ShadingType c) -> bool { } } -Graphics::Graphics() = default; +Graphics::Graphics() : screenmessages{new ScreenMessages()} {} Graphics::~Graphics() = default; void Graphics::OnAppStart() { assert(g_base->InLogicThread()); } @@ -344,43 +342,6 @@ auto Graphics::GetShadowDensity(float x, float y, float z) -> float { } } -class Graphics::ScreenMessageEntry { - public: - ScreenMessageEntry(std::string text, bool top_style, uint32_t c, - const Vector3f& color, TextureAsset* texture, - TextureAsset* tint_texture, const Vector3f& tint, - const Vector3f& tint2) - : top_style(top_style), - creation_time(c), - s_raw(std::move(text)), - color(color), - texture(texture), - tint_texture(tint_texture), - tint(tint), - tint2(tint2) {} - auto GetText() -> TextGroup&; - void UpdateTranslation(); - bool top_style; - uint32_t creation_time; - Vector3f color; - Vector3f tint; - Vector3f tint2; - std::string s_raw; - std::string s_translated; - float str_width{}; - float str_height{}; - Object::Ref texture; - Object::Ref tint_texture; - float v_smoothed{}; - bool translation_dirty{true}; - bool mesh_dirty{true}; - millisecs_t smooth_time{}; - Object::Ref shadow_mesh_; - - private: - Object::Ref s_mesh_; -}; - // Draw controls and things that lie on top of the action. void Graphics::DrawMiscOverlays(FrameDef* frame_def) { RenderPass* pass = frame_def->overlay_pass(); @@ -398,7 +359,6 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { last_fps_ = total_frames_rendered - last_total_frames_rendered_; last_total_frames_rendered_ = total_frames_rendered; } - float v{}; if (show_fps_) { char fps_str[32]; @@ -460,7 +420,7 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { { auto xf = c.ScopedTransform(); c.Translate(14.0f + (show_fps_ ? 30.0f : 0.0f), 0.1f, - kScreenMessageZDepth); + kScreenTextZDepth); c.Scale(0.7f, 0.7f); c.DrawMesh(ping_text_group_->GetElementMesh(e)); } @@ -488,7 +448,7 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { c.SetFlatness(1.0f); { auto xf = c.ScopedTransform(); - c.Translate(4.0f, (show_fps_ ? 66.0f : 40.0f), kScreenMessageZDepth); + c.Translate(4.0f, (show_fps_ ? 66.0f : 40.0f), kScreenTextZDepth); c.Scale(0.7f, 0.7f); c.DrawMesh(net_info_text_group_->GetElementMesh(e)); } @@ -516,392 +476,7 @@ void Graphics::DrawMiscOverlays(FrameDef* frame_def) { } } - // Screen messages (bottom). - { - // Delete old ones. - if (!screen_messages_.empty()) { - millisecs_t cutoff; - if (g_core->GetAppTimeMillisecs() > 5000) { - cutoff = g_core->GetAppTimeMillisecs() - 5000; - for (auto i = screen_messages_.begin(); i != screen_messages_.end();) { - if (i->creation_time < cutoff) { - auto next = i; - next++; - screen_messages_.erase(i); - i = next; - } else { - i++; - } - } - } - } - - // Delete if we have too many. - while ((screen_messages_.size()) > 4) { - screen_messages_.erase(screen_messages_.begin()); - } - - // Draw all existing. - if (!screen_messages_.empty()) { - bool vr = g_core->IsVRMode(); - - // These are less disruptive in the middle for menus but at the bottom - // during gameplay. - float start_v = g_base->graphics->screen_virtual_height() * 0.05f; - float scale; - switch (g_base->ui->scale()) { - case UIScale::kSmall: - scale = 1.5f; - break; - case UIScale::kMedium: - scale = 1.2f; - break; - default: - scale = 1.0f; - break; - } - - // Shadows. - { - SimpleComponent c(pass); - c.SetTransparent(true); - c.SetTexture( - // g_base->assets->SysTexture(SysTextureID::kSoftRectVertical)); - g_base->assets->SysTexture(SysTextureID::kShadowSharp)); - - float screen_width = g_base->graphics->screen_virtual_width(); - - v = start_v; - - millisecs_t youngest_age = 9999; - - for (auto i = screen_messages_.rbegin(); i != screen_messages_.rend(); - i++) { - // Update the translation if need be. - i->UpdateTranslation(); - - // Don't actually need the text just yet but need shadow mesh - // which is calculated as part of it. - i->GetText(); - - millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time; - youngest_age = std::min(youngest_age, age); - float s_extra = 1.0f; - if (age < 100) { - s_extra = std::min(1.2f, 1.2f * (static_cast(age) / 100.0f)); - } else if (age < 150) { - s_extra = - 1.2f - 0.2f * ((150.0f - static_cast(age)) / 50.0f); - } - - float a; - if (age > 3000) { - a = 1.0f - static_cast(age - 3000) / 2000; - } else { - a = 1; - } - a *= 0.7f; - - // if (vr) { - // a *= 0.8f; - // } - - if (i->translation_dirty) { - BA_LOG_ONCE( - LogLevel::kWarning, - "Found dirty translation on screenmessage draw pass 1; raw=" - + i->s_raw); - } - - float str_height = i->str_height; - float str_width = i->str_width; - - if ((str_width * scale) > (screen_width - 40)) { - s_extra *= ((screen_width - 40) / (str_width * scale)); - } - - float r = i->color.x; - float g = i->color.y; - float b = i->color.z; - GetSafeColor(&r, &g, &b); - - float v_extra = scale * (static_cast(youngest_age) * 0.01f); - - float fade; - if (age < 100) { - fade = 1.0f; - } else { - // Don't fade ALL the way to black; leaves a tiny bit of color - // showing which looks nice. - fade = std::max(0.07f, (200.0f - static_cast(age)) / 100.0f); - } - c.SetColor(r * fade, g * fade, b * fade, a); - - { - auto xf = c.ScopedTransform(); - - // This logic needs to run at a fixed hz or it breaks on high frame - // rates. - auto now_millisecs = pass->frame_def()->display_time_millisecs(); - i->smooth_time = std::max(i->smooth_time, now_millisecs - 100); - while (i->smooth_time < now_millisecs) { - i->smooth_time += 1000 / 60; - if (i->v_smoothed == 0.0f) { - i->v_smoothed = v + v_extra; - } else { - float smoothing = 0.8f; - i->v_smoothed = smoothing * i->v_smoothed - + (1.0f - smoothing) * (v + v_extra); - } - } - - c.Translate(screen_width * 0.5f, i->v_smoothed, - vr ? 60 : kScreenMessageZDepth); - - // if (vr) { - // // Let's drop down a bit in vr mode. - // // c.Translate(0, -10.0f, 0); - // // c.Scale((str_width + 60) * scale * s_extra, - // // (str_height + 20) * scale * s_extra); - // c.Scale(scale * s_extra, scale * s_extra); - - // // Align our bottom with where we just scaled from. - // c.Translate(0, 0.5f, 0); - { - // c.Scale((str_width + 110) * scale * s_extra, - // (str_height + 40) * scale * s_extra); - c.Scale(scale * s_extra, scale * s_extra); - c.Translate(0, 20); - - // Align our bottom with where we just scaled from. - c.Translate(0, 0.5f, 0); - } - // c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1)); - assert(i->shadow_mesh_.Exists()); - c.DrawMesh(i->shadow_mesh_.Get()); - } - - v += scale * (36 + str_height); - if (v > g_base->graphics->screen_virtual_height() + 30) { - break; - } - } - c.Submit(); - } - - // Now the strings themselves. - { - SimpleComponent c(pass); - c.SetTransparent(true); - - float screen_width = g_base->graphics->screen_virtual_width(); - v = start_v; - millisecs_t youngest_age = 9999; - - for (auto i = screen_messages_.rbegin(); i != screen_messages_.rend(); - i++) { - millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time; - youngest_age = std::min(youngest_age, age); - float s_extra = 1.0f; - if (age < 100) { - s_extra = std::min(1.2f, 1.2f * (static_cast(age) / 100.0f)); - } else if (age < 150) { - s_extra = - 1.2f - 0.2f * ((150.0f - static_cast(age)) / 50.0f); - } - float a; - if (age > 3000) { - a = 1.0f - static_cast(age - 3000) / 2000; - } else { - a = 1; - } - if (i->translation_dirty) { - BA_LOG_ONCE( - LogLevel::kWarning, - "Found dirty translation on screenmessage draw pass 2; raw=" - + i->s_raw); - } - float str_height = i->str_height; - float str_width = i->str_width; - - if ((str_width * scale) > (screen_width - 40)) { - s_extra *= ((screen_width - 40) / (str_width * scale)); - } - float r = i->color.x; - float g = i->color.y; - float b = i->color.z; - GetSafeColor(&r, &g, &b, 0.85f); - - int elem_count = i->GetText().GetElementCount(); - for (int e = 0; e < elem_count; e++) { - // Gracefully skip unloaded textures. - TextureAsset* t = i->GetText().GetElementTexture(e); - if (!t->preloaded()) { - continue; - } - c.SetTexture(t); - if (i->GetText().GetElementCanColor(e)) { - c.SetColor(r, g, b, a); - } else { - c.SetColor(1, 1, 1, a); - } - c.SetFlatness(i->GetText().GetElementMaxFlatness(e)); - { - auto xf = c.ScopedTransform(); - c.Translate(screen_width * 0.5f, i->v_smoothed, - vr ? 150 : kScreenMessageZDepth); - c.Scale(scale * s_extra, scale * s_extra); - c.Translate(0, 20); - c.DrawMesh(i->GetText().GetElementMesh(e)); - } - } - - v += scale * (36 + str_height); - if (v > g_base->graphics->screen_virtual_height() + 30) { - break; - } - } - c.Submit(); - } - } - } - - // Screen messages (top). - { - // Delete old ones. - if (!screen_messages_top_.empty()) { - millisecs_t cutoff; - if (g_core->GetAppTimeMillisecs() > 5000) { - cutoff = g_core->GetAppTimeMillisecs() - 5000; - for (auto i = screen_messages_top_.begin(); - i != screen_messages_top_.end();) { - if (i->creation_time < cutoff) { - auto next = i; - next++; - screen_messages_top_.erase(i); - i = next; - } else { - i++; - } - } - } - } - - // Delete if we have too many. - while ((screen_messages_top_.size()) > 6) { - screen_messages_top_.erase(screen_messages_top_.begin()); - } - - if (!screen_messages_top_.empty()) { - SimpleComponent c(pass); - c.SetTransparent(true); - - // Draw all existing. - float h = pass->virtual_width() - 300.0f; - v = g_base->graphics->screen_virtual_height() - 50.0f; - - float v_base = g_base->graphics->screen_virtual_height(); - float last_v = -999.0f; - - float min_spacing = 25.0f; - - for (auto i = screen_messages_top_.rbegin(); - i != screen_messages_top_.rend(); i++) { - // Update the translation if need be. - i->UpdateTranslation(); - - millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time; - float s_extra = 1.0f; - if (age < 100) { - s_extra = std::min(1.1f, 1.1f * (static_cast(age) / 100.0f)); - } else if (age < 150) { - s_extra = 1.1f - 0.1f * ((150.0f - static_cast(age)) / 50.0f); - } - - float a; - if (age > 3000) { - a = 1.0f - static_cast(age - 3000) / 2000; - } else { - a = 1; - } - - // This logic needs to run at a fixed hz or it breaks on high frame - // rates. - auto now_millisecs = pass->frame_def()->display_time_millisecs(); - i->smooth_time = std::max(i->smooth_time, now_millisecs - 100); - while (i->smooth_time < now_millisecs) { - i->smooth_time += 1000 / 60; - i->v_smoothed += 0.1f; - if (i->v_smoothed - last_v < min_spacing) { - i->v_smoothed += - 8.0f * (1.0f - ((i->v_smoothed - last_v) / min_spacing)); - } - } - last_v = i->v_smoothed; - - // Draw the image if they provided one. - if (i->texture.Exists()) { - c.Submit(); - - SimpleComponent c2(pass); - c2.SetTransparent(true); - c2.SetTexture(i->texture); - if (i->tint_texture.Exists()) { - c2.SetColorizeTexture(i->tint_texture.Get()); - c2.SetColorizeColor(i->tint.x, i->tint.y, i->tint.z); - c2.SetColorizeColor2(i->tint2.x, i->tint2.y, i->tint2.z); - c2.SetMaskTexture( - g_base->assets->SysTexture(SysTextureID::kCharacterIconMask)); - } - c2.SetColor(1, 1, 1, a); - { - auto xf = c2.ScopedTransform(); - c2.Translate(h - 14, v_base + 10 + i->v_smoothed, - kScreenMessageZDepth); - c2.Scale(22.0f * s_extra, 22.0f * s_extra); - c2.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1)); - } - c2.Submit(); - } - - float r = i->color.x; - float g = i->color.y; - float b = i->color.z; - GetSafeColor(&r, &g, &b); - - int elem_count = i->GetText().GetElementCount(); - for (int e = 0; e < elem_count; e++) { - // Gracefully skip unloaded textures. - TextureAsset* t = i->GetText().GetElementTexture(e); - if (!t->preloaded()) { - continue; - } - c.SetTexture(t); - if (i->GetText().GetElementCanColor(e)) { - c.SetColor(r, g, b, a); - } else { - c.SetColor(1, 1, 1, a); - } - c.SetShadow(-0.003f * i->GetText().GetElementUScale(e), - -0.003f * i->GetText().GetElementVScale(e), 0.0f, - 1.0f * a); - c.SetFlatness(i->GetText().GetElementMaxFlatness(e)); - c.SetMaskUV2Texture(i->GetText().GetElementMaskUV2Texture(e)); - { - auto xf = c.ScopedTransform(); - c.Translate(h, v_base + 2 + i->v_smoothed, kScreenMessageZDepth); - c.Scale(0.6f * s_extra, 0.6f * s_extra); - c.DrawMesh(i->GetText().GetElementMesh(e)); - } - } - assert(!i->translation_dirty); - v -= g_base->text_graphics->GetStringHeight(i->s_translated.c_str()) - * 0.6f - + 8.0f; - } - c.Submit(); - } - } + screenmessages->DrawMiscOverlays(frame_def); } auto Graphics::GetDebugGraph(const std::string& name, bool smoothed) @@ -947,32 +522,6 @@ void Graphics::GetSafeColor(float* red, float* green, float* blue, } } -void Graphics::AddScreenMessage(const std::string& msg, const Vector3f& color, - bool top, TextureAsset* texture, - TextureAsset* tint_texture, - const Vector3f& tint, const Vector3f& tint2) { - assert(g_base->InLogicThread()); - - // So we know we're always dealing with valid utf8. - std::string m = Utils::GetValidUTF8(msg.c_str(), "ga9msg"); - - if (top) { - float start_v = -40.0f; - if (!screen_messages_top_.empty()) { - start_v = std::min( - start_v, - std::max(-100.0f, screen_messages_top_.back().v_smoothed - 25.0f)); - } - screen_messages_top_.emplace_back(m, true, g_core->GetAppTimeMillisecs(), - color, texture, tint_texture, tint, - tint2); - screen_messages_top_.back().v_smoothed = start_v; - } else { - screen_messages_.emplace_back(m, false, g_core->GetAppTimeMillisecs(), - color, texture, tint_texture, tint, tint2); - } -} - void Graphics::Reset() { assert(g_base->InLogicThread()); fade_ = 0; @@ -982,9 +531,7 @@ void Graphics::Reset() { camera_ = Object::New(); } - // Wipe out top screen messages since they might be using textures that are - // being reset. Bottom ones are ok since they have no textures. - screen_messages_top_.clear(); + screenmessages->Reset(); } void Graphics::InitInternalComponents(FrameDef* frame_def) { @@ -1609,16 +1156,6 @@ void Graphics::DrawBlotches(FrameDef* frame_def) { } } -void Graphics::ClearScreenMessageTranslations() { - assert(g_base && g_base->InLogicThread()); - for (auto&& i : screen_messages_) { - i.translation_dirty = true; - } - for (auto&& i : screen_messages_top_) { - i.translation_dirty = true; - } -} - void Graphics::ReturnCompletedFrameDef(FrameDef* frame_def) { std::scoped_lock lock(frame_def_delete_list_mutex_); g_base->graphics->frame_def_delete_list_.push_back(frame_def); @@ -1949,46 +1486,6 @@ void Graphics::DrawRadialMeter(MeshIndexedSimpleFull* m, float amt) { } } -auto Graphics::ScreenMessageEntry::GetText() -> TextGroup& { - if (translation_dirty) { - BA_LOG_ONCE( - LogLevel::kWarning, - "Found dirty translation on screenmessage GetText; raw=" + s_raw); - } - if (!s_mesh_.Exists()) { - s_mesh_ = Object::New(); - mesh_dirty = true; - } - if (mesh_dirty) { - s_mesh_->SetText( - s_translated, - top_style ? TextMesh::HAlign::kLeft : TextMesh::HAlign::kCenter, - TextMesh::VAlign::kBottom); - - str_width = g_base->text_graphics->GetStringWidth(s_translated.c_str()); - str_height = g_base->text_graphics->GetStringHeight(s_translated.c_str()); - - if (!top_style) { - float x_extend = 40.0f; - float y_extend = 40.0f; - float y_offset = -5.0f; - float corner_radius = 60.0f; - float width_fin = str_width + x_extend * 2.0f; - float height_fin = str_height + y_extend * 2.0f; - float x_border = - NinePatchMesh::BorderForRadius(corner_radius, width_fin, height_fin); - float y_border = - NinePatchMesh::BorderForRadius(corner_radius, height_fin, width_fin); - shadow_mesh_ = Object::New( - -0.5f * width_fin, -y_extend + y_offset, 0.0f, width_fin, height_fin, - x_border, y_border, x_border, y_border); - } - - mesh_dirty = false; - } - return *s_mesh_; -} - void Graphics::OnScreenSizeChange() {} void Graphics::CalcVirtualRes_(float* x, float* y) { @@ -2042,15 +1539,6 @@ void Graphics::SetScreenResolution(float x, float y) { UpdateInitialGraphicsSettingsSend_(); } -void Graphics::ScreenMessageEntry::UpdateTranslation() { - if (translation_dirty) { - s_translated = g_base->assets->CompileResourceString( - s_raw, "Graphics::ScreenMessageEntry::UpdateTranslation"); - translation_dirty = false; - mesh_dirty = true; - } -} - auto Graphics::CubeMapFromReflectionType(ReflectionType reflection_type) -> SysCubeMapTextureID { switch (reflection_type) { @@ -2130,8 +1618,8 @@ void Graphics::LanguageChanged() { Log(LogLevel::kWarning, "Graphics::LanguageChanged() called during draw; should not happen."); } - // Also clear translations on all screen-messages. - ClearScreenMessageTranslations(); + + screenmessages->ClearScreenMessageTranslations(); } auto Graphics::GraphicsQualityFromRequest(GraphicsQualityRequest request, @@ -2154,6 +1642,7 @@ auto Graphics::GraphicsQualityFromRequest(GraphicsQualityRequest request, return GraphicsQuality::kLow; } } + auto Graphics::TextureQualityFromRequest(TextureQualityRequest request, TextureQuality auto_val) -> TextureQuality { diff --git a/src/ballistica/base/graphics/graphics.h b/src/ballistica/base/graphics/graphics.h index 1e9736ed..115f0adc 100644 --- a/src/ballistica/base/graphics/graphics.h +++ b/src/ballistica/base/graphics/graphics.h @@ -118,8 +118,6 @@ class Graphics { return res_y_virtual_; } - void ClearScreenMessageTranslations(); - // Given a point in space, returns the shadow density that should be drawn // into the shadow pass. Does this belong somewhere else? auto GetShadowDensity(float x, float y, float z) -> float; @@ -127,14 +125,6 @@ class Graphics { static void GetSafeColor(float* r, float* g, float* b, float target_intensity = 0.6f); - // Print a message to the on-screen list. - void AddScreenMessage(const std::string& msg, - const Vector3f& color = {1, 1, 1}, bool top = false, - TextureAsset* texture = nullptr, - TextureAsset* tint_texture = nullptr, - const Vector3f& tint = {1, 1, 1}, - const Vector3f& tint2 = {1, 1, 1}); - // Fade the local screen in or out over the given time period. void FadeScreen(bool to, millisecs_t time, PyObject* endcall); @@ -366,9 +356,9 @@ class Graphics { return client_context_snapshot_.Get()->Get(); } - protected: - class ScreenMessageEntry; + ScreenMessages* const screenmessages; + protected: virtual ~Graphics(); virtual void DoDrawFade(FrameDef* frame_def, float amt); static void CalcVirtualRes_(float* x, float* y); @@ -446,8 +436,6 @@ class Graphics { std::map> debug_graphs_; std::mutex frame_def_delete_list_mutex_; std::list> clean_frame_commands_; - std::list screen_messages_; - std::list screen_messages_top_; std::vector recycle_frame_defs_; std::vector blotch_indices_; std::vector blotch_verts_; @@ -466,7 +454,6 @@ class Graphics { float gyro_mag_test_{}; float overlay_node_z_depth_{}; float progress_bar_progress_{}; - float screen_gamma_{1.0f}; float shadow_lower_bottom_{-4.0f}; float shadow_lower_top_{4.0f}; float shadow_upper_bottom_{30.0f}; diff --git a/src/ballistica/base/graphics/support/screen_messages.cc b/src/ballistica/base/graphics/support/screen_messages.cc new file mode 100644 index 00000000..4dcebfd0 --- /dev/null +++ b/src/ballistica/base/graphics/support/screen_messages.cc @@ -0,0 +1,538 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/base/graphics/support/screen_messages.h" + +#include "ballistica/base/graphics/component/simple_component.h" +#include "ballistica/base/graphics/mesh/nine_patch_mesh.h" +#include "ballistica/base/graphics/text/text_graphics.h" +#include "ballistica/base/ui/ui.h" +#include "ballistica/shared/generic/utils.h" + +namespace ballistica::base { + +const float kScreenMessageZDepth{-0.06f}; + +class ScreenMessages::ScreenMessageEntry { + public: + ScreenMessageEntry(std::string text, bool top_style, uint32_t c, + const Vector3f& color, TextureAsset* texture, + TextureAsset* tint_texture, const Vector3f& tint, + const Vector3f& tint2) + : top_style(top_style), + creation_time(c), + s_raw(std::move(text)), + color(color), + texture(texture), + tint_texture(tint_texture), + tint(tint), + tint2(tint2) {} + auto GetText() -> TextGroup&; + void UpdateTranslation(); + bool top_style; + uint32_t creation_time; + Vector3f color; + Vector3f tint; + Vector3f tint2; + std::string s_raw; + std::string s_translated; + float str_width{}; + float str_height{}; + Object::Ref texture; + Object::Ref tint_texture; + float v_smoothed{}; + bool translation_dirty{true}; + bool mesh_dirty{true}; + millisecs_t smooth_time{}; + Object::Ref shadow_mesh_; + + private: + Object::Ref s_mesh_; +}; + +ScreenMessages::ScreenMessages() = default; + +void ScreenMessages::DrawMiscOverlays(FrameDef* frame_def) { + RenderPass* pass = frame_def->overlay_pass(); + + // Screen messages (bottom). + { + // Delete old ones. + if (!screen_messages_.empty()) { + millisecs_t cutoff; + if (g_core->GetAppTimeMillisecs() > 5000) { + cutoff = g_core->GetAppTimeMillisecs() - 5000; + for (auto i = screen_messages_.begin(); i != screen_messages_.end();) { + if (i->creation_time < cutoff) { + auto next = i; + next++; + screen_messages_.erase(i); + i = next; + } else { + i++; + } + } + } + } + + // Delete if we have too many. + while ((screen_messages_.size()) > 4) { + screen_messages_.erase(screen_messages_.begin()); + } + + // Draw all existing. + if (!screen_messages_.empty()) { + bool vr = g_core->IsVRMode(); + + // These are less disruptive in the middle for menus but at the bottom + // during gameplay. + float start_v = g_base->graphics->screen_virtual_height() * 0.05f; + float scale; + switch (g_base->ui->scale()) { + case UIScale::kSmall: + scale = 1.5f; + break; + case UIScale::kMedium: + scale = 1.2f; + break; + default: + scale = 1.0f; + break; + } + + // Shadows. + { + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetTexture( + // g_base->assets->SysTexture(SysTextureID::kSoftRectVertical)); + g_base->assets->SysTexture(SysTextureID::kShadowSharp)); + + float screen_width = g_base->graphics->screen_virtual_width(); + + float v = start_v; + + millisecs_t youngest_age = 9999; + + for (auto i = screen_messages_.rbegin(); i != screen_messages_.rend(); + i++) { + // Update the translation if need be. + i->UpdateTranslation(); + + // Don't actually need the text just yet but need shadow mesh + // which is calculated as part of it. + i->GetText(); + + millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time; + youngest_age = std::min(youngest_age, age); + float s_extra = 1.0f; + if (age < 100) { + s_extra = std::min(1.2f, 1.2f * (static_cast(age) / 100.0f)); + } else if (age < 150) { + s_extra = + 1.2f - 0.2f * ((150.0f - static_cast(age)) / 50.0f); + } + + float a; + if (age > 3000) { + a = 1.0f - static_cast(age - 3000) / 2000; + } else { + a = 1; + } + a *= 0.7f; + + // if (vr) { + // a *= 0.8f; + // } + + if (i->translation_dirty) { + BA_LOG_ONCE( + LogLevel::kWarning, + "Found dirty translation on screenmessage draw pass 1; raw=" + + i->s_raw); + } + + float str_height = i->str_height; + float str_width = i->str_width; + + if ((str_width * scale) > (screen_width - 40)) { + s_extra *= ((screen_width - 40) / (str_width * scale)); + } + + float r = i->color.x; + float g = i->color.y; + float b = i->color.z; + Graphics::GetSafeColor(&r, &g, &b); + + float v_extra = scale * (static_cast(youngest_age) * 0.01f); + + float fade; + if (age < 100) { + fade = 1.0f; + } else { + // Don't fade ALL the way to black; leaves a tiny bit of color + // showing which looks nice. + fade = std::max(0.07f, (200.0f - static_cast(age)) / 100.0f); + } + c.SetColor(r * fade, g * fade, b * fade, a); + + { + auto xf = c.ScopedTransform(); + + // This logic needs to run at a fixed hz or it breaks on high frame + // rates. + auto now_millisecs = pass->frame_def()->display_time_millisecs(); + i->smooth_time = std::max(i->smooth_time, now_millisecs - 100); + while (i->smooth_time < now_millisecs) { + i->smooth_time += 1000 / 60; + if (i->v_smoothed == 0.0f) { + i->v_smoothed = v + v_extra; + } else { + float smoothing = 0.8f; + i->v_smoothed = smoothing * i->v_smoothed + + (1.0f - smoothing) * (v + v_extra); + } + } + + c.Translate(screen_width * 0.5f, i->v_smoothed, + vr ? 60 : kScreenMessageZDepth); + + // if (vr) { + // // Let's drop down a bit in vr mode. + // // c.Translate(0, -10.0f, 0); + // // c.Scale((str_width + 60) * scale * s_extra, + // // (str_height + 20) * scale * s_extra); + // c.Scale(scale * s_extra, scale * s_extra); + + // // Align our bottom with where we just scaled from. + // c.Translate(0, 0.5f, 0); + { + // c.Scale((str_width + 110) * scale * s_extra, + // (str_height + 40) * scale * s_extra); + c.Scale(scale * s_extra, scale * s_extra); + c.Translate(0, 20); + + // Align our bottom with where we just scaled from. + c.Translate(0, 0.5f, 0); + } + // c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1)); + assert(i->shadow_mesh_.Exists()); + c.DrawMesh(i->shadow_mesh_.Get()); + } + + v += scale * (36 + str_height); + if (v > g_base->graphics->screen_virtual_height() + 30) { + break; + } + } + c.Submit(); + } + + // Now the strings themselves. + { + SimpleComponent c(pass); + c.SetTransparent(true); + + float screen_width = g_base->graphics->screen_virtual_width(); + float v = start_v; + millisecs_t youngest_age = 9999; + + for (auto i = screen_messages_.rbegin(); i != screen_messages_.rend(); + i++) { + millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time; + youngest_age = std::min(youngest_age, age); + float s_extra = 1.0f; + if (age < 100) { + s_extra = std::min(1.2f, 1.2f * (static_cast(age) / 100.0f)); + } else if (age < 150) { + s_extra = + 1.2f - 0.2f * ((150.0f - static_cast(age)) / 50.0f); + } + float a; + if (age > 3000) { + a = 1.0f - static_cast(age - 3000) / 2000; + } else { + a = 1; + } + if (i->translation_dirty) { + BA_LOG_ONCE( + LogLevel::kWarning, + "Found dirty translation on screenmessage draw pass 2; raw=" + + i->s_raw); + } + float str_height = i->str_height; + float str_width = i->str_width; + + if ((str_width * scale) > (screen_width - 40)) { + s_extra *= ((screen_width - 40) / (str_width * scale)); + } + float r = i->color.x; + float g = i->color.y; + float b = i->color.z; + Graphics::GetSafeColor(&r, &g, &b, 0.85f); + + int elem_count = i->GetText().GetElementCount(); + for (int e = 0; e < elem_count; e++) { + // Gracefully skip unloaded textures. + TextureAsset* t = i->GetText().GetElementTexture(e); + if (!t->preloaded()) { + continue; + } + c.SetTexture(t); + if (i->GetText().GetElementCanColor(e)) { + c.SetColor(r, g, b, a); + } else { + c.SetColor(1, 1, 1, a); + } + c.SetFlatness(i->GetText().GetElementMaxFlatness(e)); + { + auto xf = c.ScopedTransform(); + c.Translate(screen_width * 0.5f, i->v_smoothed, + vr ? 150 : kScreenMessageZDepth); + c.Scale(scale * s_extra, scale * s_extra); + c.Translate(0, 20); + c.DrawMesh(i->GetText().GetElementMesh(e)); + } + } + + v += scale * (36 + str_height); + if (v > g_base->graphics->screen_virtual_height() + 30) { + break; + } + } + c.Submit(); + } + } + } + + // Screen messages (top). + { + // Delete old ones. + if (!screen_messages_top_.empty()) { + millisecs_t cutoff; + if (g_core->GetAppTimeMillisecs() > 5000) { + cutoff = g_core->GetAppTimeMillisecs() - 5000; + for (auto i = screen_messages_top_.begin(); + i != screen_messages_top_.end();) { + if (i->creation_time < cutoff) { + auto next = i; + next++; + screen_messages_top_.erase(i); + i = next; + } else { + i++; + } + } + } + } + + // Delete if we have too many. + while ((screen_messages_top_.size()) > 6) { + screen_messages_top_.erase(screen_messages_top_.begin()); + } + + if (!screen_messages_top_.empty()) { + SimpleComponent c(pass); + c.SetTransparent(true); + + // Draw all existing. + float h = pass->virtual_width() - 300.0f; + float v = g_base->graphics->screen_virtual_height() - 50.0f; + + float v_base = g_base->graphics->screen_virtual_height(); + float last_v = -999.0f; + + float min_spacing = 25.0f; + + for (auto i = screen_messages_top_.rbegin(); + i != screen_messages_top_.rend(); i++) { + // Update the translation if need be. + i->UpdateTranslation(); + + millisecs_t age = g_core->GetAppTimeMillisecs() - i->creation_time; + float s_extra = 1.0f; + if (age < 100) { + s_extra = std::min(1.1f, 1.1f * (static_cast(age) / 100.0f)); + } else if (age < 150) { + s_extra = 1.1f - 0.1f * ((150.0f - static_cast(age)) / 50.0f); + } + + float a; + if (age > 3000) { + a = 1.0f - static_cast(age - 3000) / 2000; + } else { + a = 1; + } + + // This logic needs to run at a fixed hz or it breaks on high frame + // rates. + auto now_millisecs = pass->frame_def()->display_time_millisecs(); + i->smooth_time = std::max(i->smooth_time, now_millisecs - 100); + while (i->smooth_time < now_millisecs) { + i->smooth_time += 1000 / 60; + i->v_smoothed += 0.1f; + if (i->v_smoothed - last_v < min_spacing) { + i->v_smoothed += + 8.0f * (1.0f - ((i->v_smoothed - last_v) / min_spacing)); + } + } + last_v = i->v_smoothed; + + // Draw the image if they provided one. + if (i->texture.Exists()) { + c.Submit(); + + SimpleComponent c2(pass); + c2.SetTransparent(true); + c2.SetTexture(i->texture); + if (i->tint_texture.Exists()) { + c2.SetColorizeTexture(i->tint_texture.Get()); + c2.SetColorizeColor(i->tint.x, i->tint.y, i->tint.z); + c2.SetColorizeColor2(i->tint2.x, i->tint2.y, i->tint2.z); + c2.SetMaskTexture( + g_base->assets->SysTexture(SysTextureID::kCharacterIconMask)); + } + c2.SetColor(1, 1, 1, a); + { + auto xf = c2.ScopedTransform(); + c2.Translate(h - 14, v_base + 10 + i->v_smoothed, + kScreenMessageZDepth); + c2.Scale(22.0f * s_extra, 22.0f * s_extra); + c2.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1)); + } + c2.Submit(); + } + + float r = i->color.x; + float g = i->color.y; + float b = i->color.z; + Graphics::GetSafeColor(&r, &g, &b); + + int elem_count = i->GetText().GetElementCount(); + for (int e = 0; e < elem_count; e++) { + // Gracefully skip unloaded textures. + TextureAsset* t = i->GetText().GetElementTexture(e); + if (!t->preloaded()) { + continue; + } + c.SetTexture(t); + if (i->GetText().GetElementCanColor(e)) { + c.SetColor(r, g, b, a); + } else { + c.SetColor(1, 1, 1, a); + } + c.SetShadow(-0.003f * i->GetText().GetElementUScale(e), + -0.003f * i->GetText().GetElementVScale(e), 0.0f, + 1.0f * a); + c.SetFlatness(i->GetText().GetElementMaxFlatness(e)); + c.SetMaskUV2Texture(i->GetText().GetElementMaskUV2Texture(e)); + { + auto xf = c.ScopedTransform(); + c.Translate(h, v_base + 2 + i->v_smoothed, kScreenMessageZDepth); + c.Scale(0.6f * s_extra, 0.6f * s_extra); + c.DrawMesh(i->GetText().GetElementMesh(e)); + } + } + assert(!i->translation_dirty); + v -= g_base->text_graphics->GetStringHeight(i->s_translated.c_str()) + * 0.6f + + 8.0f; + } + c.Submit(); + } + } +} + +void ScreenMessages::AddScreenMessage(const std::string& msg, + const Vector3f& color, bool top, + TextureAsset* texture, + TextureAsset* tint_texture, + const Vector3f& tint, + const Vector3f& tint2) { + assert(g_base->InLogicThread()); + + // So we know we're always dealing with valid utf8. + std::string m = Utils::GetValidUTF8(msg.c_str(), "ga9msg"); + + if (top) { + float start_v = -40.0f; + if (!screen_messages_top_.empty()) { + start_v = std::min( + start_v, + std::max(-100.0f, screen_messages_top_.back().v_smoothed - 25.0f)); + } + screen_messages_top_.emplace_back(m, true, g_core->GetAppTimeMillisecs(), + color, texture, tint_texture, tint, + tint2); + screen_messages_top_.back().v_smoothed = start_v; + } else { + screen_messages_.emplace_back(m, false, g_core->GetAppTimeMillisecs(), + color, texture, tint_texture, tint, tint2); + } +} + +void ScreenMessages::Reset() { + // Wipe out top screen messages since they might be using textures that are + // being reset. Bottom ones are ok since they have no textures. + screen_messages_top_.clear(); +} + +void ScreenMessages::ClearScreenMessageTranslations() { + assert(g_base && g_base->InLogicThread()); + for (auto&& i : screen_messages_) { + i.translation_dirty = true; + } + for (auto&& i : screen_messages_top_) { + i.translation_dirty = true; + } +} + +auto ScreenMessages::ScreenMessageEntry::GetText() -> TextGroup& { + if (translation_dirty) { + BA_LOG_ONCE( + LogLevel::kWarning, + "Found dirty translation on screenmessage GetText; raw=" + s_raw); + } + if (!s_mesh_.Exists()) { + s_mesh_ = Object::New(); + mesh_dirty = true; + } + if (mesh_dirty) { + s_mesh_->SetText( + s_translated, + top_style ? TextMesh::HAlign::kLeft : TextMesh::HAlign::kCenter, + TextMesh::VAlign::kBottom); + + str_width = g_base->text_graphics->GetStringWidth(s_translated.c_str()); + str_height = g_base->text_graphics->GetStringHeight(s_translated.c_str()); + + if (!top_style) { + float x_extend = 40.0f; + float y_extend = 40.0f; + float y_offset = -5.0f; + float corner_radius = 60.0f; + float width_fin = str_width + x_extend * 2.0f; + float height_fin = str_height + y_extend * 2.0f; + float x_border = + NinePatchMesh::BorderForRadius(corner_radius, width_fin, height_fin); + float y_border = + NinePatchMesh::BorderForRadius(corner_radius, height_fin, width_fin); + shadow_mesh_ = Object::New( + -0.5f * width_fin, -y_extend + y_offset, 0.0f, width_fin, height_fin, + x_border, y_border, x_border, y_border); + } + + mesh_dirty = false; + } + return *s_mesh_; +} + +void ScreenMessages::ScreenMessageEntry::UpdateTranslation() { + if (translation_dirty) { + s_translated = g_base->assets->CompileResourceString( + s_raw, "Graphics::ScreenMessageEntry::UpdateTranslation"); + translation_dirty = false; + mesh_dirty = true; + } +} + +} // namespace ballistica::base diff --git a/src/ballistica/base/graphics/support/screen_messages.h b/src/ballistica/base/graphics/support/screen_messages.h new file mode 100644 index 00000000..91652149 --- /dev/null +++ b/src/ballistica/base/graphics/support/screen_messages.h @@ -0,0 +1,37 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_BASE_GRAPHICS_SUPPORT_SCREEN_MESSAGES_H_ +#define BALLISTICA_BASE_GRAPHICS_SUPPORT_SCREEN_MESSAGES_H_ + +#include "ballistica/base/base.h" +#include "ballistica/shared/math/vector3f.h" + +namespace ballistica::base { + +/// Wrangles a set of screen-messages. +class ScreenMessages { + public: + ScreenMessages(); + + void ClearScreenMessageTranslations(); + + // Print a message to the on-screen list. + void AddScreenMessage(const std::string& msg, + const Vector3f& color = {1, 1, 1}, bool top = false, + TextureAsset* texture = nullptr, + TextureAsset* tint_texture = nullptr, + const Vector3f& tint = {1, 1, 1}, + const Vector3f& tint2 = {1, 1, 1}); + + void DrawMiscOverlays(FrameDef* frame_def); + void Reset(); + + private: + class ScreenMessageEntry; + std::list screen_messages_; + std::list screen_messages_top_; +}; + +} // namespace ballistica::base + +#endif // BALLISTICA_BASE_GRAPHICS_SUPPORT_SCREEN_MESSAGES_H_ diff --git a/src/ballistica/base/input/device/test_input.cc b/src/ballistica/base/input/device/test_input.cc index 7e20a291..b7491c2e 100644 --- a/src/ballistica/base/input/device/test_input.cc +++ b/src/ballistica/base/input/device/test_input.cc @@ -22,7 +22,7 @@ TestInput::~TestInput() { } void TestInput::Reset() { - assert(g_core->InMainThread()); + assert(g_base->InLogicThread()); reset_ = true; } @@ -33,7 +33,7 @@ void TestInput::HandleAlreadyPressedTwice() { } void TestInput::Process(millisecs_t time) { - assert(g_core->InMainThread()); + assert(g_base->InLogicThread()); if (reset_) { reset_ = false; diff --git a/src/ballistica/base/input/device/test_input.h b/src/ballistica/base/input/device/test_input.h index 34e2e4ce..b89accf4 100644 --- a/src/ballistica/base/input/device/test_input.h +++ b/src/ballistica/base/input/device/test_input.h @@ -16,20 +16,21 @@ class TestInput { private: void HandleAlreadyPressedTwice(); + int lr_{}; int ud_{}; - bool jump_pressed_{}; - bool bomb_pressed_{}; - bool pickup_pressed_{}; - bool punch_pressed_{}; + int join_press_count_{}; + bool jump_pressed_ : 1 {}; + bool bomb_pressed_ : 1 {}; + bool pickup_pressed_ : 1 {}; + bool punch_pressed_ : 1 {}; + bool print_non_join_ : 1 {}; + bool print_already_did2_ : 1 {}; + bool reset_ : 1 {true}; millisecs_t next_event_time_{}; millisecs_t join_start_time_{}; millisecs_t join_end_time_{9999}; - int join_press_count_{}; - bool reset_{true}; JoystickInput* joystick_{}; - bool print_non_join_{}; - bool print_already_did2_{}; }; } // namespace ballistica::base diff --git a/src/ballistica/base/input/input.cc b/src/ballistica/base/input/input.cc index 14b5c443..5b33f2a4 100644 --- a/src/ballistica/base/input/input.cc +++ b/src/ballistica/base/input/input.cc @@ -8,7 +8,6 @@ #include "ballistica/base/graphics/support/camera.h" #include "ballistica/base/input/device/joystick_input.h" #include "ballistica/base/input/device/keyboard_input.h" -#include "ballistica/base/input/device/test_input.h" #include "ballistica/base/input/device/touch_input.h" #include "ballistica/base/logic/logic.h" #include "ballistica/base/python/base_python.h" @@ -762,58 +761,6 @@ void Input::PrintLockLabels_() { Log(LogLevel::kError, s); } -void Input::ProcessStressTesting(int player_count) { - assert(g_core->InMainThread()); - assert(player_count >= 0); - - millisecs_t time = g_core->GetAppTimeMillisecs(); - - // FIXME: If we don't check for stress_test_last_leave_time_ we totally - // confuse the game.. need to be able to survive that. - - // Kill some off if we have too many. - while (static_cast(test_inputs_.size()) > player_count) { - delete test_inputs_.front(); - test_inputs_.pop_front(); - } - - // If we have less than full test-inputs, add one randomly. - if (static_cast(test_inputs_.size()) < player_count - && ((rand() % 1000 < 10))) { // NOLINT - test_inputs_.push_back(new TestInput()); - } - - // Every so often lets kill the oldest one off. - if (explicit_bool(true)) { - if (test_inputs_.size() > 0 && (rand() % 2000 < 3)) { // NOLINT - stress_test_last_leave_time_ = time; - - // Usually do oldest; sometimes newest. - if (rand() % 5 == 0) { // NOLINT - delete test_inputs_.back(); - test_inputs_.pop_back(); - } else { - delete test_inputs_.front(); - test_inputs_.pop_front(); - } - } - } - - if (time - stress_test_time_ > 1000) { - stress_test_time_ = time; // reset.. - for (auto& test_input : test_inputs_) { - (*test_input).Reset(); - } - } - - while (stress_test_time_ < time) { - stress_test_time_++; - for (auto& test_input : test_inputs_) { - (*test_input).Process(stress_test_time_); - } - } -} - void Input::PushTextInputEvent(const std::string& text) { assert(g_base->logic->event_loop()); g_base->logic->event_loop()->PushCall([this, text] { diff --git a/src/ballistica/base/input/input.h b/src/ballistica/base/input/input.h index e256a2ff..9c33ecd2 100644 --- a/src/ballistica/base/input/input.h +++ b/src/ballistica/base/input/input.h @@ -114,7 +114,6 @@ class Input { // something. auto HaveControllerWithPlayer() -> bool; auto HaveRemoteAppController() -> bool; - void ProcessStressTesting(int player_count); auto keyboard_input() const -> KeyboardInput* { return keyboard_input_; } auto keyboard_input_2() const -> KeyboardInput* { return keyboard_input_2_; } void CreateTouchInput(); @@ -205,7 +204,6 @@ class Input { std::list input_lock_permanent_labels_; std::list input_unlock_permanent_labels_; std::list recent_input_locks_unlocks_; - std::list test_inputs_; std::list newly_connected_controllers_; std::list newly_disconnected_controllers_; std::unordered_map > @@ -214,8 +212,6 @@ class Input { std::set keys_held_; millisecs_t last_input_device_count_update_time_{}; millisecs_t last_input_temp_lock_time_{}; - millisecs_t stress_test_time_{}; - millisecs_t stress_test_last_leave_time_{}; void* single_touch_{}; KeyboardInput* keyboard_input_{}; KeyboardInput* keyboard_input_2_{}; diff --git a/src/ballistica/base/input/support/remote_app_server.cc b/src/ballistica/base/input/support/remote_app_server.cc index 1ab678df..d5f78b95 100644 --- a/src/ballistica/base/input/support/remote_app_server.cc +++ b/src/ballistica/base/input/support/remote_app_server.cc @@ -5,6 +5,7 @@ #include "ballistica/base/assets/assets.h" #include "ballistica/base/audio/audio.h" #include "ballistica/base/graphics/graphics.h" +#include "ballistica/base/graphics/support/screen_messages.h" #include "ballistica/base/input/input.h" #include "ballistica/base/logic/logic.h" #include "ballistica/base/networking/network_reader.h" @@ -162,7 +163,8 @@ void RemoteAppServer::HandleData(int socket, uint8_t* buffer, size_t amt, g_base->assets->GetResourceString("controllerDisconnectedText"); Utils::StringReplaceOne(&s, "${CONTROLLER}", m); g_base->logic->event_loop()->PushCall([s] { - g_base->graphics->AddScreenMessage(s, Vector3f(1, 1, 1)); + g_base->graphics->screenmessages->AddScreenMessage( + s, Vector3f(1, 1, 1)); }); g_base->logic->event_loop()->PushCall([] { g_base->audio->PlaySound( @@ -369,8 +371,10 @@ auto RemoteAppServer::GetClient(int request_id, struct sockaddr* addr, std::string s = g_base->assets->GetResourceString("controllerReconnectedText"); Utils::StringReplaceOne(&s, "${CONTROLLER}", m); - g_base->logic->event_loop()->PushCall( - [s] { g_base->graphics->AddScreenMessage(s, Vector3f(1, 1, 1)); }); + g_base->logic->event_loop()->PushCall([s] { + g_base->graphics->screenmessages->AddScreenMessage(s, + Vector3f(1, 1, 1)); + }); g_base->logic->event_loop()->PushCall([] { g_base->audio->PlaySound( g_base->assets->SysSound(SysSoundID::kGunCock)); @@ -416,8 +420,10 @@ auto RemoteAppServer::GetClient(int request_id, struct sockaddr* addr, std::string s = g_base->assets->GetResourceString("controllerConnectedText"); Utils::StringReplaceOne(&s, "${CONTROLLER}", m); - g_base->logic->event_loop()->PushCall( - [s] { g_base->graphics->AddScreenMessage(s, Vector3f(1, 1, 1)); }); + g_base->logic->event_loop()->PushCall([s] { + g_base->graphics->screenmessages->AddScreenMessage(s, + Vector3f(1, 1, 1)); + }); g_base->logic->event_loop()->PushCall([] { g_base->audio->PlaySound( diff --git a/src/ballistica/base/logic/logic.cc b/src/ballistica/base/logic/logic.cc index a57852ec..909a8ddd 100644 --- a/src/ballistica/base/logic/logic.cc +++ b/src/ballistica/base/logic/logic.cc @@ -580,7 +580,7 @@ void Logic::UpdatePendingWorkTimer_() { // If there's loading to do, keep at it rather vigorously. if (have_pending_loads_) { assert(process_pending_work_timer_); - process_pending_work_timer_->SetLength(1000); + process_pending_work_timer_->SetLength(1 * 1000); } else { // Otherwise we've got nothing to do; go to sleep until something // changes. diff --git a/src/ballistica/base/platform/apple/base_platform_apple.cc b/src/ballistica/base/platform/apple/base_platform_apple.cc index 833d8003..9bfc4a3e 100644 --- a/src/ballistica/base/platform/apple/base_platform_apple.cc +++ b/src/ballistica/base/platform/apple/base_platform_apple.cc @@ -19,7 +19,7 @@ namespace ballistica::base { BasePlatformApple::BasePlatformApple() { // On iOS, keep the device from falling asleep in our app #if BA_OSTYPE_IOS_TVOS - AppleUtils::DisableIdleTimer(); + // AppleUtils::DisableIdleTimer(); #endif } @@ -41,7 +41,7 @@ void BasePlatformApple::RestorePurchases() { void BasePlatformApple::PurchaseAck(const std::string& purchase, const std::string& order_id) { -#if BA_XCODE_BUILD +#if BA_XCODE_BUILD && BA_USE_STORE_KIT AppleUtils::PurchaseAck(purchase, order_id); #else BasePlatform::PurchaseAck(purchase, order_id); diff --git a/src/ballistica/base/python/methods/python_methods_app.cc b/src/ballistica/base/python/methods/python_methods_app.cc index ba299479..265906fd 100644 --- a/src/ballistica/base/python/methods/python_methods_app.cc +++ b/src/ballistica/base/python/methods/python_methods_app.cc @@ -9,7 +9,6 @@ #include "ballistica/base/logic/logic.h" #include "ballistica/base/python/base_python.h" #include "ballistica/base/python/support/python_context_call_runnable.h" -#include "ballistica/base/support/stress_test.h" #include "ballistica/base/ui/dev_console.h" #include "ballistica/base/ui/ui.h" #include "ballistica/shared/foundation/event_loop.h" @@ -784,32 +783,6 @@ static PyMethodDef PyEnvDef = { "This info is now exposed through babase.App; refer to those docs for\n" "info on specific elements."}; -// -------------------------- set_stress_testing ------------------------------- - -static auto PySetStressTesting(PyObject* self, PyObject* args) -> PyObject* { - BA_PYTHON_TRY; - int enable; - int player_count; - if (!PyArg_ParseTuple(args, "pi", &enable, &player_count)) { - return nullptr; - } - g_base->app_adapter->PushMainThreadCall([enable, player_count] { - g_base->stress_test()->Set(enable, player_count); - }); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -static PyMethodDef PySetStressTestingDef = { - "set_stress_testing", // name - PySetStressTesting, // method - METH_VARARGS, // flags - - "set_stress_testing(testing: bool, player_count: int) -> None\n" - "\n" - "(internal)", -}; - // -------------------------------- emit_log ----------------------------------- static auto PyEmitLog(PyObject* self, PyObject* args, PyObject* keywds) @@ -1702,7 +1675,6 @@ auto PythonMethodsApp::GetMethods() -> std::vector { PyCanDisplayFullUnicodeDef, PyEmitLogDef, PyV1CloudLogDef, - PySetStressTestingDef, PyEnvDef, PyPreEnvDef, PyCommitConfigDef, diff --git a/src/ballistica/base/python/methods/python_methods_graphics.cc b/src/ballistica/base/python/methods/python_methods_graphics.cc index 1e489461..d2ab871f 100644 --- a/src/ballistica/base/python/methods/python_methods_graphics.cc +++ b/src/ballistica/base/python/methods/python_methods_graphics.cc @@ -6,6 +6,7 @@ #include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/graphics.h" #include "ballistica/base/graphics/support/camera.h" +#include "ballistica/base/graphics/support/screen_messages.h" #include "ballistica/base/graphics/text/text_graphics.h" #include "ballistica/base/logic/logic.h" #include "ballistica/base/python/base_python.h" @@ -74,7 +75,7 @@ static auto PyScreenMessage(PyObject* self, PyObject* args, PyObject* keywds) } // This version simply displays it locally. - g_base->graphics->AddScreenMessage(message_str, color); + g_base->graphics->screenmessages->AddScreenMessage(message_str, color); Py_RETURN_NONE; BA_PYTHON_CATCH; diff --git a/src/ballistica/base/support/app_timer.h b/src/ballistica/base/support/app_timer.h index 876c3a65..6289ab75 100644 --- a/src/ballistica/base/support/app_timer.h +++ b/src/ballistica/base/support/app_timer.h @@ -13,20 +13,22 @@ namespace ballistica::base { class AppTimer : public Object { public: - AppTimer(microsecs_t length, bool repeat, Runnable* runnable) { + AppTimer(seconds_t length, bool repeat, Runnable* runnable) { assert(g_base->InLogicThread()); - timer_id_ = base::g_base->logic->NewAppTimer(length, repeat, runnable); + timer_id_ = base::g_base->logic->NewAppTimer( + static_cast(length * 1000000.0), repeat, runnable); } template - static auto New(microsecs_t length, bool repeat, const F& lambda) { + static auto New(seconds_t length, bool repeat, const F& lambda) { return Object::New(length, repeat, NewLambdaRunnable(lambda).Get()); } - void SetLength(microsecs_t length) { + void SetLength(seconds_t length) { assert(g_base->InLogicThread()); - base::g_base->logic->SetAppTimerLength(timer_id_, length); + base::g_base->logic->SetAppTimerLength( + timer_id_, static_cast(length * 1000000.0)); } ~AppTimer() override { diff --git a/src/ballistica/base/support/display_timer.h b/src/ballistica/base/support/display_timer.h index 1936ed8d..f8f72db8 100644 --- a/src/ballistica/base/support/display_timer.h +++ b/src/ballistica/base/support/display_timer.h @@ -13,21 +13,24 @@ namespace ballistica::base { class DisplayTimer : public Object { public: - DisplayTimer(microsecs_t length, bool repeat, Runnable* runnable) { + DisplayTimer(seconds_t length, bool repeat, Runnable* runnable) { assert(g_base->InLogicThread()); - timer_id_ = base::g_base->logic->NewDisplayTimer(length, repeat, runnable); + timer_id_ = base::g_base->logic->NewDisplayTimer( + static_cast(length * 1000000.0), repeat, runnable); } template - static auto New(microsecs_t length, bool repeat, const F& lambda) { + static auto New(seconds_t length, bool repeat, const F& lambda) { return Object::New(length, repeat, NewLambdaRunnable(lambda).Get()); } - void SetLength(microsecs_t length) { + void SetLength(seconds_t length) { assert(g_base->InLogicThread()); - base::g_base->logic->SetDisplayTimerLength(timer_id_, length); + base::g_base->logic->SetDisplayTimerLength( + timer_id_, static_cast(length * 1000000.0)); } + ~DisplayTimer() override { assert(g_base->InLogicThread()); base::g_base->logic->DeleteDisplayTimer(timer_id_); diff --git a/src/ballistica/base/support/repeater.cc b/src/ballistica/base/support/repeater.cc index 8528ce12..899a9cce 100644 --- a/src/ballistica/base/support/repeater.cc +++ b/src/ballistica/base/support/repeater.cc @@ -27,9 +27,8 @@ Repeater::Repeater(seconds_t initial_delay, seconds_t repeat_delay, return; } // Kick off our initial delay timer (generally the longer one). - weak_this->timer_ = DisplayTimer::New( - static_cast(weak_this->initial_delay_ * 1000000.0), - false, [weak_this] { + weak_this->timer_ = + DisplayTimer::New(weak_this->initial_delay_, false, [weak_this] { // Timer should not have fired if we died. assert(weak_this.Exists()); weak_this->runnable_->RunAndLogErrors(); @@ -38,9 +37,8 @@ Repeater::Repeater(seconds_t initial_delay, seconds_t repeat_delay, return; } // Kick off our repeat timer (generally the short one). - weak_this->timer_ = DisplayTimer::New( - static_cast(weak_this->repeat_delay_ * 1000000.0), - true, [weak_this] { + weak_this->timer_ = + DisplayTimer::New(weak_this->repeat_delay_, true, [weak_this] { // Timer should not have fired if we died. assert(weak_this.Exists()); weak_this->runnable_->RunAndLogErrors(); diff --git a/src/ballistica/base/support/stress_test.h b/src/ballistica/base/support/stress_test.h deleted file mode 100644 index 6da0ec7b..00000000 --- a/src/ballistica/base/support/stress_test.h +++ /dev/null @@ -1,25 +0,0 @@ -// Released under the MIT License. See LICENSE for details. - -#ifndef BALLISTICA_BASE_SUPPORT_STRESS_TEST_H_ -#define BALLISTICA_BASE_SUPPORT_STRESS_TEST_H_ - -#include "ballistica/shared/ballistica.h" - -namespace ballistica::base { - -class StressTest { - public: - void Set(bool enable, int player_count); - void Update(); - - private: - FILE* stress_test_stats_file_{}; - millisecs_t last_stress_test_update_time_{}; - bool stress_testing_{}; - int stress_test_player_count_{8}; - int last_total_frames_rendered_{}; -}; - -} // namespace ballistica::base - -#endif // BALLISTICA_BASE_SUPPORT_STRESS_TEST_H_ diff --git a/src/ballistica/base/ui/dev_console.cc b/src/ballistica/base/ui/dev_console.cc index 793617a2..1f0ccab8 100644 --- a/src/ballistica/base/ui/dev_console.cc +++ b/src/ballistica/base/ui/dev_console.cc @@ -6,7 +6,6 @@ #include "ballistica/base/app_mode/app_mode.h" #include "ballistica/base/audio/audio.h" #include "ballistica/base/graphics/component/simple_component.h" -#include "ballistica/base/graphics/mesh/nine_patch_mesh.h" #include "ballistica/base/graphics/text/text_graphics.h" #include "ballistica/base/logic/logic.h" #include "ballistica/base/platform/base_platform.h" @@ -1299,14 +1298,13 @@ void DevConsole::Draw(FrameDef* frame_def) { if (!carat_mesh_.Exists()) { UpdateCarat_(); } - millisecs_t real_time = pass->frame_def()->app_time_millisecs(); - if (real_time % 200 < 100 - || (real_time - last_carat_x_change_time_ < 100)) { + millisecs_t app_time = pass->frame_def()->app_time_millisecs(); + millisecs_t since_change = app_time - last_carat_x_change_time_; + if (since_change < 300 || since_change % 1000 < 500) { SimpleComponent c(pass); c.SetTransparent(true); c.SetTexture(g_base->assets->SysTexture(SysTextureID::kShadow)); c.SetColor(0.8, 0.0, 1.0, 0.3f); - // c.SetPremultiplied(true); { auto xf = c.ScopedTransform(); auto carat_x = GetCaratX_(); diff --git a/src/ballistica/classic/classic.cc b/src/ballistica/classic/classic.cc index 11abf286..56a42e41 100644 --- a/src/ballistica/classic/classic.cc +++ b/src/ballistica/classic/classic.cc @@ -2,7 +2,9 @@ #include "ballistica/classic/classic.h" +#include "ballistica/base/support/app_timer.h" #include "ballistica/classic/python/classic_python.h" +#include "ballistica/classic/support/stress_test.h" #include "ballistica/classic/support/v1_account.h" #include "ballistica/core/platform/core_platform.h" #include "ballistica/scene_v1/python/scene_v1_python.h" @@ -54,7 +56,9 @@ void ClassicFeatureSet::OnModuleExec(PyObject* module) { } ClassicFeatureSet::ClassicFeatureSet() - : python{new ClassicPython()}, v1_account{new V1Account()} { + : python{new ClassicPython()}, + v1_account{new V1Account()}, + stress_test_{new StressTest()} { // We're a singleton. If there's already one of us, something's wrong. assert(g_classic == nullptr); } diff --git a/src/ballistica/classic/classic.h b/src/ballistica/classic/classic.h index 97cbe97f..efba8d9d 100644 --- a/src/ballistica/classic/classic.h +++ b/src/ballistica/classic/classic.h @@ -28,6 +28,7 @@ namespace ballistica::classic { // Predeclared types our feature-set provides. class ClassicFeatureSet; class ClassicPython; +class StressTest; class V1Account; enum class V1AccountType { @@ -107,9 +108,12 @@ class ClassicFeatureSet : public FeatureSetNativeComponent, void set_v1_account_type(V1AccountType tp) { v1_account_type_ = tp; } void PlayMusic(const std::string& music_type, bool continuous) override; + auto* stress_test() const { return stress_test_; } + private: ClassicFeatureSet(); V1AccountType v1_account_type_{V1AccountType::kInvalid}; + StressTest* stress_test_; }; } // namespace ballistica::classic diff --git a/src/ballistica/classic/python/methods/python_methods_classic.cc b/src/ballistica/classic/python/methods/python_methods_classic.cc index 6f6765c0..9fab53da 100644 --- a/src/ballistica/classic/python/methods/python_methods_classic.cc +++ b/src/ballistica/classic/python/methods/python_methods_classic.cc @@ -4,7 +4,10 @@ #include "ballistica/base/graphics/graphics.h" #include "ballistica/base/graphics/support/camera.h" +#include "ballistica/base/logic/logic.h" +#include "ballistica/classic/support/stress_test.h" #include "ballistica/scene_v1/support/scene_v1_app_mode.h" +#include "ballistica/shared/foundation/event_loop.h" #include "ballistica/shared/python/python.h" #include "ballistica/shared/python/python_sys.h" @@ -145,10 +148,42 @@ static PyMethodDef PyValueTestDef = { "(internal)", }; +// -------------------------- set_stress_testing ------------------------------- + +static auto PySetStressTesting(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + int enable; + int player_count; + if (!PyArg_ParseTuple(args, "pi", &enable, &player_count)) { + return nullptr; + } + // g_base->app_adapter->PushMainThreadCall([enable, player_count] { + // g_base->stress_test()->Set(enable, player_count); + // }); + g_base->logic->event_loop()->PushCall([enable, player_count] { + g_classic->stress_test()->Set(enable, player_count); + }); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +static PyMethodDef PySetStressTestingDef = { + "set_stress_testing", // name + PySetStressTesting, // method + METH_VARARGS, // flags + + "set_stress_testing(testing: bool, player_count: int) -> None\n" + "\n" + "(internal)", +}; + // ----------------------------------------------------------------------------- auto PythonMethodsClassic::GetMethods() -> std::vector { - return {PyValueTestDef}; + return { + PyValueTestDef, + PySetStressTestingDef, + }; } #pragma clang diagnostic pop diff --git a/src/ballistica/base/support/stress_test.cc b/src/ballistica/classic/support/stress_test.cc similarity index 61% rename from src/ballistica/base/support/stress_test.cc rename to src/ballistica/classic/support/stress_test.cc index 0438e972..b92e6074 100644 --- a/src/ballistica/base/support/stress_test.cc +++ b/src/ballistica/classic/support/stress_test.cc @@ -1,15 +1,18 @@ // Released under the MIT License. See LICENSE for details. -#include "ballistica/base/support/stress_test.h" +#include "ballistica/classic/support/stress_test.h" #include "ballistica/base/graphics/graphics_server.h" #include "ballistica/base/graphics/renderer/renderer.h" +#include "ballistica/base/input/device/test_input.h" #include "ballistica/base/input/input.h" +#include "ballistica/base/support/app_timer.h" +#include "ballistica/classic/classic.h" -namespace ballistica::base { +namespace ballistica::classic { void StressTest::Set(bool enable, int player_count) { - assert(g_core->InMainThread()); + assert(g_base->InLogicThread()); bool was_stress_testing = stress_testing_; stress_testing_ = enable; stress_test_player_count_ = player_count; @@ -28,17 +31,22 @@ void StressTest::Set(bool enable, int player_count) { // Assume zero if there's no graphics yet. last_total_frames_rendered_ = 0; } + + update_timer_ = base::AppTimer::New(1.0 / 30.0, true, [this] { Update(); }); + } + if (!stress_testing_) { + update_timer_.Clear(); } } void StressTest::Update() { - assert(g_core->InMainThread()); + assert(g_base->InLogicThread()); // Handle a little misc stuff here. // If we're currently running stress-tests, update that stuff. if (stress_testing_ && g_base->input) { // Update our fake inputs to make our dudes run around. - g_base->input->ProcessStressTesting(stress_test_player_count_); + ProcessInputs(stress_test_player_count_); // Every 10 seconds update our stress-test stats. millisecs_t t = g_core->GetAppTimeMillisecs(); @@ -51,10 +59,10 @@ void StressTest::Update() { stress_test_stats_file_ = g_core->platform->FOpen(f_name.c_str(), "wb"); if (stress_test_stats_file_ != nullptr) { - fprintf( - stress_test_stats_file_, - "time,averageFps,nodes,meshes,collision_meshes,textures,sounds," - "pssMem,sharedDirtyMem,privateDirtyMem\n"); + fprintf(stress_test_stats_file_, + "time,averageFps,nodes,meshes,collision_meshes,textures," + "sounds," + "pssMem,sharedDirtyMem,privateDirtyMem\n"); fflush(stress_test_stats_file_); } } @@ -98,4 +106,56 @@ void StressTest::Update() { } } -} // namespace ballistica::base +void StressTest::ProcessInputs(int player_count) { + assert(g_base->InLogicThread()); + assert(player_count >= 0); + + millisecs_t time = g_core->GetAppTimeMillisecs(); + + // FIXME: If we don't check for stress_test_last_leave_time_ we totally + // confuse the game.. need to be able to survive that. + + // Kill some off if we have too many. + while (static_cast(test_inputs_.size()) > player_count) { + delete test_inputs_.front(); + test_inputs_.pop_front(); + } + + // If we have less than full test-inputs, add one randomly. + if (static_cast(test_inputs_.size()) < player_count + && ((rand() % 1000 < 10))) { // NOLINT + test_inputs_.push_back(new base::TestInput()); + } + + // Every so often lets kill the oldest one off. + if (explicit_bool(true)) { + if (test_inputs_.size() > 0 && (rand() % 2000 < 3)) { // NOLINT + stress_test_last_leave_time_ = time; + + // Usually do oldest; sometimes newest. + if (rand() % 5 == 0) { // NOLINT + delete test_inputs_.back(); + test_inputs_.pop_back(); + } else { + delete test_inputs_.front(); + test_inputs_.pop_front(); + } + } + } + + if (time - stress_test_time_ > 1000) { + stress_test_time_ = time; // reset.. + for (auto& test_input : test_inputs_) { + (*test_input).Reset(); + } + } + + while (stress_test_time_ < time) { + stress_test_time_++; + for (auto& test_input : test_inputs_) { + (*test_input).Process(stress_test_time_); + } + } +} + +} // namespace ballistica::classic diff --git a/src/ballistica/classic/support/stress_test.h b/src/ballistica/classic/support/stress_test.h new file mode 100644 index 00000000..96c5fd71 --- /dev/null +++ b/src/ballistica/classic/support/stress_test.h @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CLASSIC_SUPPORT_STRESS_TEST_H_ +#define BALLISTICA_CLASSIC_SUPPORT_STRESS_TEST_H_ + +#include "ballistica/base/base.h" +#include "ballistica/shared/ballistica.h" +#include "ballistica/shared/foundation/object.h" + +namespace ballistica::classic { + +class StressTest { + public: + void Set(bool enable, int player_count); + void Update(); + + private: + void ProcessInputs(int player_count); + std::list test_inputs_; + + millisecs_t stress_test_time_{}; + millisecs_t stress_test_last_leave_time_{}; + int stress_test_player_count_{8}; + int last_total_frames_rendered_{}; + bool stress_testing_ : 1 {}; + millisecs_t last_stress_test_update_time_{}; + FILE* stress_test_stats_file_{}; + Object::Ref update_timer_{}; +}; + +} // namespace ballistica::classic + +#endif // BALLISTICA_CLASSIC_SUPPORT_STRESS_TEST_H_ diff --git a/src/ballistica/core/platform/apple/core_platform_apple.cc b/src/ballistica/core/platform/apple/core_platform_apple.cc index ac64502f..5c9d4cd6 100644 --- a/src/ballistica/core/platform/apple/core_platform_apple.cc +++ b/src/ballistica/core/platform/apple/core_platform_apple.cc @@ -42,7 +42,8 @@ auto CorePlatformApple::GetRealLegacyDeviceUUID(std::string* uuid) -> bool { return true; #endif #if BA_OSTYPE_IOS_TVOS - *uuid = base::AppleUtils::GetIOSUUID(); + *uuid = std::string(BallisticaKit::UIKitFromCpp::GetLegacyDeviceUUID()); + // *uuid = base::AppleUtils::GetIOSUUID(); return true; #endif return false; @@ -84,7 +85,9 @@ auto CorePlatformApple::GetDeviceUUIDInputs() -> std::list { #endif // BA_OSTYPE_MACOS #if BA_OSTYPE_IOS_TVOS - out.push_back(base::AppleUtils::GetIOSUUID()); + // out.push_back(base::AppleUtils::GetIOSUUID()); + out.push_back( + std::string(BallisticaKit::UIKitFromCpp::GetLegacyDeviceUUID())); #endif return out; } @@ -121,7 +124,8 @@ auto CorePlatformApple::DoHasTouchScreen() -> bool { auto CorePlatformApple::GetDefaultUIScale() -> UIScale { #if BA_OSTYPE_IOS - if (base::AppleUtils::IsTablet()) { + if (BallisticaKit::UIKitFromCpp::IsTablet()) { + // if (base::AppleUtils::IsTablet()) { return UIScale::kMedium; } else { return UIScale::kSmall; @@ -278,21 +282,21 @@ void CorePlatformApple::ShowOnlineScoreUI(const std::string& show, #endif } -auto CorePlatformApple::NewAutoReleasePool() -> void* { -#if BA_XCODE_BUILD - return base::AppleUtils::NewAutoReleasePool(); -#else - return CorePlatform::NewAutoReleasePool(); -#endif -} +// auto CorePlatformApple::NewAutoReleasePool() -> void* { +// #if BA_XCODE_BUILD +// return base::AppleUtils::NewAutoReleasePool(); +// #else +// return CorePlatform::NewAutoReleasePool(); +// #endif +// } -void CorePlatformApple::DrainAutoReleasePool(void* pool) { -#if BA_XCODE_BUILD - base::AppleUtils::DrainAutoReleasePool(pool); -#else - CorePlatform::DrainAutoReleasePool(pool); -#endif -} +// void CorePlatformApple::DrainAutoReleasePool(void* pool) { +// #if BA_XCODE_BUILD +// base::AppleUtils::DrainAutoReleasePool(pool); +// #else +// CorePlatform::DrainAutoReleasePool(pool); +// #endif +// } void CorePlatformApple::GameCenterLogin() { #if BA_USE_GAME_CENTER @@ -331,50 +335,68 @@ void CorePlatformApple::OpenDirExternally(const std::string& path) { void CorePlatformApple::MacMusicAppInit() { #if BA_OSTYPE_MACOS && BA_XCODE_BUILD - base::AppleUtils::MacMusicAppInit(); + BallisticaKit::CocoaFromCpp::MacMusicAppInit(); + // base::AppleUtils::MacMusicAppInit(); #else CorePlatform::MacMusicAppInit(); #endif } auto CorePlatformApple::MacMusicAppGetVolume() -> int { #if BA_OSTYPE_MACOS && BA_XCODE_BUILD - return static_cast(base::AppleUtils::MacMusicAppGetVolume()); + return BallisticaKit::CocoaFromCpp::MacMusicAppGetVolume(); + // return static_cast(base::AppleUtils::MacMusicAppGetVolume()); #else return CorePlatform::MacMusicAppGetVolume(); #endif } void CorePlatformApple::MacMusicAppSetVolume(int volume) { #if BA_OSTYPE_MACOS && BA_XCODE_BUILD - base::AppleUtils::MacMusicAppSetVolume(volume); + return BallisticaKit::CocoaFromCpp::MacMusicAppSetVolume(volume); + // base::AppleUtils::MacMusicAppSetVolume(volume); #else CorePlatform::MacMusicAppSetVolume(volume); #endif } + +// KILL THIS. void CorePlatformApple::MacMusicAppGetLibrarySource() { #if BA_OSTYPE_MACOS && BA_XCODE_BUILD - base::AppleUtils::MacMusicAppGetLibrarySource(); + // base::AppleUtils::MacMusicAppGetLibrarySource(); #else CorePlatform::MacMusicAppGetLibrarySource(); #endif } void CorePlatformApple::MacMusicAppStop() { #if BA_OSTYPE_MACOS && BA_XCODE_BUILD - base::AppleUtils::MacMusicAppStop(); + return BallisticaKit::CocoaFromCpp::MacMusicAppStop(); + // base::AppleUtils::MacMusicAppStop(); #else CorePlatform::MacMusicAppStop(); #endif } + auto CorePlatformApple::MacMusicAppPlayPlaylist(const std::string& playlist) -> bool { #if BA_OSTYPE_MACOS && BA_XCODE_BUILD - return base::AppleUtils::MacMusicAppPlayPlaylist(playlist.c_str()); + return BallisticaKit::CocoaFromCpp::MacMusicAppPlayPlaylist(playlist); + // return base::AppleUtils::MacMusicAppPlayPlaylist(playlist.c_str()); #else return CorePlatform::MacMusicAppPlayPlaylist(playlist); #endif } + auto CorePlatformApple::MacMusicAppGetPlaylists() -> std::list { #if BA_OSTYPE_MACOS && BA_XCODE_BUILD - return base::AppleUtils::MacMusicAppGetPlaylists(); + BallisticaKit::CocoaFromCpp::MacMusicAppGetPlaylists(); + // mac_music_app_playlists_.clear(); + // mac_music_app_playlists_.push_back("foof"); + // mac_music_app_playlists_.push_back("barf"); + // std::list out; + // for (auto&& val : vals) { + // out.push_back(std::string(val)); + // } + // return out; + return mac_music_app_playlists(); #else return CorePlatform::MacMusicAppGetPlaylists(); #endif diff --git a/src/ballistica/core/platform/apple/core_platform_apple.h b/src/ballistica/core/platform/apple/core_platform_apple.h index 215cb74a..bfbb019e 100644 --- a/src/ballistica/core/platform/apple/core_platform_apple.h +++ b/src/ballistica/core/platform/apple/core_platform_apple.h @@ -42,8 +42,8 @@ class CorePlatformApple : public CorePlatform { -> bool override; void ShowOnlineScoreUI(const std::string& show, const std::string& game, const std::string& game_version) override; - auto NewAutoReleasePool() -> void* override; - void DrainAutoReleasePool(void* pool) override; + // auto NewAutoReleasePool() -> void* override; + // void DrainAutoReleasePool(void* pool) override; void ResetAchievements() override; void GameCenterLogin() override; auto IsOSPlayingMusic() -> bool override; @@ -63,8 +63,6 @@ class CorePlatformApple : public CorePlatform { protected: auto DoGetDataDirectoryMonolithicDefault() -> std::string override; - - private: }; } // namespace ballistica::core diff --git a/src/ballistica/core/platform/core_platform.cc b/src/ballistica/core/platform/core_platform.cc index 92973146..f4303b89 100644 --- a/src/ballistica/core/platform/core_platform.cc +++ b/src/ballistica/core/platform/core_platform.cc @@ -721,9 +721,9 @@ auto CorePlatform::DemangleCXXSymbol(const std::string& s) -> std::string { #endif } -auto CorePlatform::NewAutoReleasePool() -> void* { throw Exception(); } +// auto CorePlatform::NewAutoReleasePool() -> void* { throw Exception(); } -void CorePlatform::DrainAutoReleasePool(void* pool) { throw Exception(); } +// void CorePlatform::DrainAutoReleasePool(void* pool) { throw Exception(); } void CorePlatform::ResetAchievements() { Log(LogLevel::kError, "ResetAchievements() unimplemented"); diff --git a/src/ballistica/core/platform/core_platform.h b/src/ballistica/core/platform/core_platform.h index b3890170..96a1bbe8 100644 --- a/src/ballistica/core/platform/core_platform.h +++ b/src/ballistica/core/platform/core_platform.h @@ -205,8 +205,8 @@ class CorePlatform { #pragma mark APPLE ------------------------------------------------------------- - virtual auto NewAutoReleasePool() -> void*; - virtual void DrainAutoReleasePool(void* pool); + // virtual auto NewAutoReleasePool() -> void*; + // virtual void DrainAutoReleasePool(void* pool); // FIXME: Can we consolidate these with the general music playback calls? virtual void MacMusicAppInit(); virtual auto MacMusicAppGetVolume() -> int; @@ -396,6 +396,11 @@ class CorePlatform { /// Are we being run from a terminal? (should we show prompts, etc?). auto is_stdin_a_terminal() const { return is_stdin_a_terminal_; } + void set_music_app_playlists(const std::list& playlists) { + mac_music_app_playlists_ = playlists; + } + auto mac_music_app_playlists() const { return mac_music_app_playlists_; } + protected: /// Are we being run from a terminal? (should we show prompts, etc?). virtual auto GetIsStdinATerminal() -> bool; @@ -445,7 +450,6 @@ class CorePlatform { /// 'noteworthy' or presented to the user as standard Log() calls are. virtual void HandleDebugLog(const std::string& msg); - protected: CorePlatform(); virtual ~CorePlatform(); @@ -462,6 +466,9 @@ class CorePlatform { std::string legacy_device_uuid_; std::string volatile_data_dir_; std::string replays_dir_; + + // temp. + std::list mac_music_app_playlists_; }; /// For capturing and printing stack-traces and related errors. Platforms diff --git a/src/ballistica/scene_v1/python/methods/python_methods_scene.cc b/src/ballistica/scene_v1/python/methods/python_methods_scene.cc index ab7e2e73..9cf3846e 100644 --- a/src/ballistica/scene_v1/python/methods/python_methods_scene.cc +++ b/src/ballistica/scene_v1/python/methods/python_methods_scene.cc @@ -6,6 +6,7 @@ #include "ballistica/base/dynamics/bg/bg_dynamics.h" #include "ballistica/base/graphics/graphics.h" +#include "ballistica/base/graphics/support/screen_messages.h" #include "ballistica/base/python/base_python.h" #include "ballistica/base/python/class/python_class_simple_sound.h" #include "ballistica/base/python/support/python_context_call_runnable.h" @@ -755,7 +756,7 @@ static auto PyBroadcastMessage(PyObject* self, PyObject* args, PyObject* keywds) } // Now display it locally. - g_base->graphics->AddScreenMessage( + g_base->graphics->screenmessages->AddScreenMessage( message, color, static_cast(top), texture ? texture->texture_data() : nullptr, tint_texture ? tint_texture->texture_data() : nullptr, tint_color, diff --git a/src/ballistica/scene_v1/support/client_session.cc b/src/ballistica/scene_v1/support/client_session.cc index d10e11e4..f796c64c 100644 --- a/src/ballistica/scene_v1/support/client_session.cc +++ b/src/ballistica/scene_v1/support/client_session.cc @@ -5,6 +5,7 @@ #include "ballistica/base/audio/audio.h" #include "ballistica/base/dynamics/bg/bg_dynamics.h" #include "ballistica/base/graphics/graphics.h" +#include "ballistica/base/graphics/support/screen_messages.h" #include "ballistica/base/networking/networking.h" #include "ballistica/scene_v1/assets/scene_collision_mesh.h" #include "ballistica/scene_v1/assets/scene_mesh.h" @@ -819,7 +820,7 @@ void ClientSession::Update(int time_advance_millisecs, double time_advance) { std::string s = ReadString(); float f[9]; ReadFloats(9, f); - g_base->graphics->AddScreenMessage( + g_base->graphics->screenmessages->AddScreenMessage( s, Vector3f(f[0], f[1], f[2]), true, texture->texture_data(), tint_texture->texture_data(), Vector3f(f[3], f[4], f[5]), Vector3f(f[6], f[7], f[8])); diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 3eeb626b..57058bcc 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 21531; +const int kEngineBuildNumber = 21543; const char* kEngineVersion = "1.7.28"; const int kEngineApiVersion = 8; diff --git a/src/ballistica/shared/foundation/event_loop.cc b/src/ballistica/shared/foundation/event_loop.cc index c04245e7..88b7ad5b 100644 --- a/src/ballistica/shared/foundation/event_loop.cc +++ b/src/ballistica/shared/foundation/event_loop.cc @@ -251,24 +251,24 @@ void EventLoop::WaitForNextEvent_(bool single_cycle) { // Note to self (Oct '23): can probably kill this at some point, // but am still using some non-ARC objc stuff from logic thread // so should keep it around just a bit longer just in case. -void EventLoop::LoopUpkeep_(bool single_cycle) { - assert(g_core); - // Keep our autorelease pool clean on mac/ios - // FIXME: Should define a CorePlatform::ThreadHelper or something - // so we don't have platform-specific code here. -#if BA_XCODE_BUILD - // Let's not do autorelease pools when being called ad-hoc, - // since in that case we're part of another run loop - // (and its crashing on drain for some reason) - if (!single_cycle) { - if (auto_release_pool_) { - g_core->platform->DrainAutoReleasePool(auto_release_pool_); - auto_release_pool_ = nullptr; - } - auto_release_pool_ = g_core->platform->NewAutoReleasePool(); - } -#endif -} +// void EventLoop::LoopUpkeep_(bool single_cycle) { +// assert(g_core); +// // Keep our autorelease pool clean on mac/ios +// // FIXME: Should define a CorePlatform::ThreadHelper or something +// // so we don't have platform-specific code here. +// #if BA_XCODE_BUILD +// // Let's not do autorelease pools when being called ad-hoc, +// // since in that case we're part of another run loop +// // (and its crashing on drain for some reason) +// if (!single_cycle) { +// if (auto_release_pool_) { +// g_core->platform->DrainAutoReleasePool(auto_release_pool_); +// auto_release_pool_ = nullptr; +// } +// auto_release_pool_ = g_core->platform->NewAutoReleasePool(); +// } +// #endif +//} void EventLoop::RunToCompletion() { Run_(false); } void EventLoop::RunSingleCycle() { Run_(true); } @@ -276,7 +276,7 @@ void EventLoop::RunSingleCycle() { Run_(true); } void EventLoop::Run_(bool single_cycle) { assert(g_core); while (true) { - LoopUpkeep_(single_cycle); + // LoopUpkeep_(single_cycle); WaitForNextEvent_(single_cycle); diff --git a/src/ballistica/shared/foundation/event_loop.h b/src/ballistica/shared/foundation/event_loop.h index 5a9649e6..9bb2d057 100644 --- a/src/ballistica/shared/foundation/event_loop.h +++ b/src/ballistica/shared/foundation/event_loop.h @@ -149,11 +149,11 @@ class EventLoop { void BootstrapThread_(); - void LoopUpkeep_(bool single_cycle); + // void LoopUpkeep_(bool single_cycle); // FIXME: Should generalize this to some sort of PlatformThreadData class. #if BA_XCODE_BUILD - void* auto_release_pool_{}; + // void* auto_release_pool_{}; #endif EventLoopID identifier_{EventLoopID::kInvalid}; diff --git a/src/ballistica/ui_v1/widget/button_widget.cc b/src/ballistica/ui_v1/widget/button_widget.cc index e8ce6a37..29c6db6a 100644 --- a/src/ballistica/ui_v1/widget/button_widget.cc +++ b/src/ballistica/ui_v1/widget/button_widget.cc @@ -57,7 +57,7 @@ void ButtonWidget::OnRepeatTimerExpired() { DoActivate(true); // Speed up repeats after the first. - repeat_timer_->SetLength(150); + repeat_timer_->SetLength(0.150); } else { repeat_timer_.Clear(); } @@ -165,7 +165,9 @@ void ButtonWidget::Draw(base::RenderPass* pass, bool draw_transparent) { // Account for our icon if we have it. float s_width_available = std::max(30.0f, width_ - 30); - if (show_icons) s_width_available -= (34.0f * icon_scale_); + if (show_icons) { + s_width_available -= (34.0f * icon_scale_); + } if ((string_width * string_scale) > s_width_available) { float squish_scale = s_width_available / (string_width * string_scale); @@ -486,7 +488,7 @@ auto ButtonWidget::HandleMessage(const base::WidgetMessage& m) -> bool { if (repeat_) { repeat_timer_ = base::AppTimer::New( - 300, true, [this] { OnRepeatTimerExpired(); }); + 0.3, true, [this] { OnRepeatTimerExpired(); }); // If we're a repeat button we trigger immediately. // (waiting till mouse up sort of defeats the purpose here) diff --git a/src/ballistica/ui_v1/widget/h_scroll_widget.cc b/src/ballistica/ui_v1/widget/h_scroll_widget.cc index c8d23371..40b832fc 100644 --- a/src/ballistica/ui_v1/widget/h_scroll_widget.cc +++ b/src/ballistica/ui_v1/widget/h_scroll_widget.cc @@ -406,7 +406,7 @@ auto HScrollWidget::HandleMessage(const base::WidgetMessage& m) -> bool { // scrolling has started. if (static_cast(m.type)) { touch_delay_timer_ = base::AppTimer::New( - 150, false, [this] { OnTouchDelayTimerExpired(); }); + 0.150, false, [this] { OnTouchDelayTimerExpired(); }); } // If we're handling a scroll-touch, take note that we need to diff --git a/src/ballistica/ui_v1/widget/scroll_widget.cc b/src/ballistica/ui_v1/widget/scroll_widget.cc index de48022c..67ce6d2c 100644 --- a/src/ballistica/ui_v1/widget/scroll_widget.cc +++ b/src/ballistica/ui_v1/widget/scroll_widget.cc @@ -331,7 +331,7 @@ auto ScrollWidget::HandleMessage(const base::WidgetMessage& m) -> bool { // click if it hasn't turned into a scroll or a child scroll. if (!child_is_scrolling_) { touch_delay_timer_ = base::AppTimer::New( - 150, false, [this] { OnTouchDelayTimerExpired(); }); + 0.150, false, [this] { OnTouchDelayTimerExpired(); }); } } } diff --git a/tools/batools/pruneincludes.py b/tools/batools/pruneincludes.py index 3a282fa0..b34fa2be 100755 --- a/tools/batools/pruneincludes.py +++ b/tools/batools/pruneincludes.py @@ -60,8 +60,15 @@ class Pruner: entries = self._get_entries() + processed_paths = set[str]() + with tempfile.TemporaryDirectory() as tempdir: for entry in entries: + # Entries list might have repeats. + if entry.file in processed_paths: + continue + processed_paths.add(entry.file) + if not entry.file.startswith(cwd): raise CleanError( f'compile-commands file {entry.file}' diff --git a/tools/batools/xcodeproject.py b/tools/batools/xcodeproject.py index 911efc4f..42ba6339 100644 --- a/tools/batools/xcodeproject.py +++ b/tools/batools/xcodeproject.py @@ -50,7 +50,7 @@ def update_xcode_project( for p in all_source_files if os.path.splitext(p)[1] in suffixes ), - has_app_delegate_mm=True, + # has_app_delegate_mm=True, projname=projname, ) else: @@ -64,7 +64,7 @@ def update_xcode_project( for p in all_source_files if os.path.splitext(p)[1] in suffixes ), - has_app_delegate_mm=True, + # has_app_delegate_mm=True, projname=projname, ) @@ -83,7 +83,7 @@ class Updater: existing_data: str, sources: list[str], projname: str, - has_app_delegate_mm: bool = False, + # has_app_delegate_mm: bool = False, ) -> None: if not path.endswith('.xcodeproj'): raise RuntimeError(f"Path does not end in .xcodeproj: '{path}'.") @@ -93,7 +93,7 @@ class Updater: self.existing_data = existing_data self.sources = sources self.project = None - self.has_app_delegate_mm = has_app_delegate_mm + # self.has_app_delegate_mm = has_app_delegate_mm # Project name variations. self.pnameu = projname @@ -165,8 +165,8 @@ class Updater: srcgrp = self._get_unique_group(f'{self.pnameu} Shared') self.add_paths(srcgrp) - if self.has_app_delegate_mm: - self.mod_app_delegate_mm() + # if self.has_app_delegate_mm: + # self.mod_app_delegate_mm() # Groups we made should be sorted already since we sorted while # building them, but let's sort the top level group we placed @@ -302,6 +302,7 @@ class Updater: ) return grps[0] + # (No longer used; just leaving here as reference though) def mod_app_delegate_mm(self) -> None: """Set per-file compiler flags.""" files = self.project.get_files_by_name('app_delegate.mm')