mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 21:37:57 +08:00
server lag fix and timer cleanup
This commit is contained in:
parent
7b21a7fccc
commit
782a8773a4
88
.efrocachemap
generated
88
.efrocachemap
generated
@ -4072,50 +4072,50 @@
|
||||
"build/assets/workspace/ninjafightplug.py": "https://files.ballistica.net/cache/ba1/18/4b/787a9267e17be3c49966072581a5",
|
||||
"build/assets/workspace/onslaughtplug.py": "https://files.ballistica.net/cache/ba1/20/f6/4ce9bc3c1f3732f6adf8237fbe9b",
|
||||
"build/assets/workspace/runaroundplug.py": "https://files.ballistica.net/cache/ba1/a5/30/9058181df0b1255bf6950cbc7813",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/8c/ed/211ad9931645ec21344cc09943cf",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/71/df/89649ebeee912d3671994700ca98",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/3a/55/2e767201ff0210baf2aab336b962",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/96/b7/14b9ff3221e0643c5808408889a0",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/96/a6/67826a50b92ef1b97c9350357bde",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/1a/00/5f26c8e62d546190ef1a0e5d86c1",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/e9/d9/c37edc30a6d87dc6a3fff69cd69d",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/f0/96/eafa605033a621f0024ce23e8506",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/e7/0c/e5d1f7f76463dab3a593c7e39d28",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/23/98/40563ec129aeae3ae29fce9a4098",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/19/db/025a2e4224285384ca5138b528b9",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/3b/04/f7f76fbbb71c51d398999b91d962",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/ce/65/019b91c6590778d7e2f32a6dc86d",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/70/5d/74932199660c0faa295fc8b331e5",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/e1/37/98c5e9424f0c180db6aa16a0a2e9",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/c9/3f/3dc59e05f156376638a59e606954",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/6b/2b/6a98ef5411ea98d0190aae33ca8a",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/65/82/defe87b3e240bbabd8194beb71a2",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/39/10/6e8db73db72f65b094401dc66972",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/45/5d/a65990370464ca038cd0a1be680a",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/3c/a8/5487ece199be8717cead6de157e3",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/9d/71/77a0ae15f3216c51da44ccefeb87",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/8c/de/a04c75afaee10276fedbd6dc12dd",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/c1/45/f2143d53646891111b648a6cc014",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/4c/0c/2afa4f64c6030ba37cacdb62fb4d",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/d2/0a/0d4b99f583a4e7a55761c5493c06",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/5e/ff/b8cd37fe6d5fa5df6a7bc6103ecc",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/84/e3/815f8ba4a1c0ff4b01e44bd95682",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/10/98/48262f1e81f07154c28cfec87ee9",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/6e/97/e8029482a29578a9f6cc15813265",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/5d/ac/fbe75dcd9f4a4461552cdaf8a3be",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/94/ec/cce65d8f6f76e240597b073f17e7",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/a9/15/89ec9af80cf169f837ea6c3c365d",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/e1/d8/0949e33c04570cae7dafaf906770",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/91/c5/f1c4dcdd2233d6ffc280db77ec99",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/20/e5/3b83e186b63a95d704c69a6b5b76",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/bf/fa/f79dc4a7ca33a8cca9df0547eef4",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/9e/3c/09855cda12586dbba55884a259b0",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/47/f1/3eadde3dcabd1b0b9be32a7f247f",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/f3/f6/51991b000385d553f35563df4190",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/a3/7d/cae2bd2e4daf11f90e73937170fc",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/1e/cc/ab11419f2d792b8738605a1f3a24",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/11/eb/55affc8d77ccac52c0b8fd128ad7",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/5a/57/2df7d185467abcca2287a4410ee8",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/35/07/d6fdff6fe4bd1e69a223c3a620aa",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/3f/67/cdaf89a3ae87c92e7a69ead533d1",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/16/a7/857b4c971a3129c69ec7daa1d0bc",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/0e/65/21ae4a44d94cbd82e7f3a3a122b5",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/62/a4/5f233d592052188accbe49ab0ec2",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/2c/dd/417f3aefe03828172469ed81630b",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/2e/97/df7ecde6a7e82fd4a579cce8bae7",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/83/f7/dbf7a4c6a63ae84f0e0eff4974c3",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/57/1e/8208bc0c7de0def0e7cc399b412b",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/54/1f/f718b7159d58a8af4ab14caa9d06",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/78/f2/59cd0bcd802c0a977a3352ec8be4",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/d7/09/709476d32c9d060225c8717366bc",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/e9/9a/4a1c14fd9ef8d96aa1052242671c",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/04/87/e2d9488fa7d0e44fcd2ae386ab5d",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/24/6f/c8a72d8010e6e3e721d64e1a80c7",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/9d/6a/806d3b173c7739a04cad0df3cb32",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/e0/70/aaf9248064e99fef9b934b52f486",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/91/0c/6e58dac0732e20de8536fa187a16",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/8a/95/23c7dadc9d94aabef250b352a5cd",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/c9/b8/afeaa6080be3c45430f73900bbcf",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/d9/56/b0a16db98621500b473844ec39d6",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/57/f9/f304c67d9958574b6b35de2ad13d",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/04/55/a41ad832c081ff421039827d16c1",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/65/a7/2008753f3dbe890a730ca081ee8f",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/a1/1f/cb01b3a6773cd8fc1a3ed1c320c5",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/49/a7/b65d9e50fc94a82e88e5802020b4",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/25/28/a1657fe9f97172fee036f8f31173",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/5c/5b/2edf7105dcd7a653fa449af25bab",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/c9/02/670a183eed30429ebd3c61a26229",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/7d/50/17bb34179dd958f1e3563634dab5",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/3f/9d/30372ce093efd265ac89955ef774",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/ca/89/4d9fb94ed0ec2e5cc36f40908f34",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/cd/87/606884c0a1d45fbfc57db6c635cb",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/88/1a/1ea680450c3c9bc97147df4bf99d",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/91/b3/31b980ca2a000871408cbc7923e3",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/67/d1/8b98ad3d0d67bf6bc23c2c9167cf",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/6d/bf/7b03106aec7089c1ff956aee1569",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/06/df/2cfcaec212dcb94432a247a631e7",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/e8/60/503824952252ee34eedfb779aa0e",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/28/1a/dfdeaffd5d7f997679ba534117db",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "https://files.ballistica.net/cache/ba1/47/6c/d9fa447b2fae36bfaa6ec1344a66",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "https://files.ballistica.net/cache/ba1/b0/c3/0f4e4ab477affd0451e44476ad0a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "https://files.ballistica.net/cache/ba1/c9/a3/3fd02b8024684d98a361e3c0ec70",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "https://files.ballistica.net/cache/ba1/1c/20/a80e4f7eea1631ed3da2a1279340",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "https://files.ballistica.net/cache/ba1/52/c6/c11130af7b10d6c0321add5518fa",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "https://files.ballistica.net/cache/ba1/38/c3/1dedd5e74f2508efc5974c8815a1",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "https://files.ballistica.net/cache/ba1/ea/6a/6a4721b144e5e297b542d2a0eea2",
|
||||
|
||||
2
.idea/dictionaries/ericf.xml
generated
2
.idea/dictionaries/ericf.xml
generated
@ -135,6 +135,7 @@
|
||||
<w>apptime</w>
|
||||
<w>apptimer</w>
|
||||
<w>apptimers</w>
|
||||
<w>apptimesecs</w>
|
||||
<w>apputils</w>
|
||||
<w>archbase</w>
|
||||
<w>archivepath</w>
|
||||
@ -2595,6 +2596,7 @@
|
||||
<w>sirplus</w>
|
||||
<w>sitebuiltins</w>
|
||||
<w>skey</w>
|
||||
<w>sleepsecs</w>
|
||||
<w>sline</w>
|
||||
<w>slist</w>
|
||||
<w>slists</w>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
### 1.7.20 (build 21107, api 8, 2023-06-14)
|
||||
### 1.7.20 (build 21108, api 8, 2023-06-14)
|
||||
|
||||
- This seems like a good time for a `refactoring` release in anticipation of
|
||||
changes coming in 1.8. Basically this means that a lot of things will be
|
||||
@ -321,6 +321,12 @@
|
||||
would draw incorrectly.
|
||||
- (build 21106) Fixed an issue where in-game ping would always display green no
|
||||
matter how bad the ping was.
|
||||
- (build 21107) Upped internal display-timer resolution from milliseconds to
|
||||
microseconds.
|
||||
- (build 21107) Finished implementing new scheduling system for headless mode.
|
||||
This should fix the issue where 1.7.20 servers would have 100ms of lag by
|
||||
default. Server performance should now be equal to or better than 1.7.19.
|
||||
Please holler if not.
|
||||
|
||||
### 1.7.19 (build 20997, api 7, 2023-01-19)
|
||||
|
||||
|
||||
2
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
2
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
@ -92,6 +92,7 @@
|
||||
<w>apptime</w>
|
||||
<w>apptimer</w>
|
||||
<w>apptimers</w>
|
||||
<w>apptimesecs</w>
|
||||
<w>archbase</w>
|
||||
<w>archos</w>
|
||||
<w>argindex</w>
|
||||
@ -1499,6 +1500,7 @@
|
||||
<w>sincestr</w>
|
||||
<w>sisssssssss</w>
|
||||
<w>sixteenbits</w>
|
||||
<w>sleepsecs</w>
|
||||
<w>slist</w>
|
||||
<w>slists</w>
|
||||
<w>smod</w>
|
||||
|
||||
@ -28,7 +28,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21107
|
||||
TARGET_BALLISTICA_BUILD = 21108
|
||||
TARGET_BALLISTICA_VERSION = '1.7.20'
|
||||
|
||||
_g_env_config: EnvConfig | None = None
|
||||
|
||||
@ -386,6 +386,8 @@ class PluginWindow(bui.Window):
|
||||
sel_name = 'Settings'
|
||||
elif sel == self._back_button:
|
||||
sel_name = 'Back'
|
||||
elif sel == self._scrollwidget:
|
||||
sel_name = 'Scroll'
|
||||
else:
|
||||
raise ValueError(f'unrecognized selection \'{sel}\'')
|
||||
assert bui.app.classic is not None
|
||||
|
||||
@ -42,6 +42,10 @@ void AppMode::ChangeGameSpeed(int offs) {}
|
||||
|
||||
void AppMode::StepDisplayTime() {}
|
||||
|
||||
auto AppMode::GetHeadlessDisplayStep() -> microsecs_t {
|
||||
return kAppModeMaxHeadlessDisplayStep;
|
||||
}
|
||||
|
||||
auto AppMode::GetPartySize() const -> int { return 0; }
|
||||
|
||||
auto AppMode::GetNetworkDebugString() -> std::string { return ""; }
|
||||
|
||||
@ -9,6 +9,15 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
/// The max amount of time a headless app can sleep if no events are pending.
|
||||
/// This should not be *too* high or it might cause delays when going from
|
||||
/// no events present to events present.
|
||||
const microsecs_t kAppModeMaxHeadlessDisplayStep{500000};
|
||||
|
||||
/// The min amount of time a headless app can sleep. This provides an upper
|
||||
/// limit on stepping overhead in cases where events are densely packed.
|
||||
const microsecs_t kAppModeMinHeadlessDisplayStep{1000};
|
||||
|
||||
/// Represents 'what the app is doing'. The global app-mode can be switched
|
||||
/// as the app is running. Be aware that, unlike the App/App classes
|
||||
/// which operate in the main thread, most functionality here is based in the
|
||||
@ -32,10 +41,20 @@ class AppMode {
|
||||
/// Apply the app config.
|
||||
virtual void ApplyAppConfig();
|
||||
|
||||
/// Update the logic thread. Can be called at any frequency; generally
|
||||
/// corresponds to frame draws or a fixed timer.
|
||||
/// Update the logic thread for a new display-time. Can be called at any
|
||||
/// frequency. In gui builds, generally corresponds with frame drawing. In
|
||||
/// headless builds, generally corresponds with scene stepping or other
|
||||
/// scheduled events. Check values on g_base->logic to see current
|
||||
/// display-time and most recent step size applied.
|
||||
virtual void StepDisplayTime();
|
||||
|
||||
/// Called right after stepping; should return the exact microseconds
|
||||
/// between the current display time and the next event the app-mode has
|
||||
/// scheduled. If no events are pending, should return
|
||||
/// kAppModeMaxHeadlessDisplayStep. This will only be called on headless
|
||||
/// builds.
|
||||
virtual auto GetHeadlessDisplayStep() -> microsecs_t;
|
||||
|
||||
/// Create a delegate for an input-device.
|
||||
/// Return a raw pointer allocated using Object::NewDeferred.
|
||||
virtual auto CreateInputDeviceDelegate(InputDevice* device)
|
||||
|
||||
@ -238,6 +238,9 @@ void BaseFeatureSet::set_app_mode(AppMode* mode) {
|
||||
input->RebuildInputDeviceDelegates();
|
||||
|
||||
app_mode_->OnActivate();
|
||||
|
||||
// Let some stuff know.
|
||||
logic->OnAppModeChanged();
|
||||
} catch (const Exception& exc) {
|
||||
// Anything going wrong while switching app-modes leaves us in an
|
||||
// undefined state; don't try to continue.
|
||||
|
||||
@ -220,8 +220,10 @@ void Logic::CompleteAppBootstrapping() {
|
||||
// rate (10hz) to keep things efficient. Anyone dealing in display-time
|
||||
// should be able to handle a wide variety of rates anyway.
|
||||
if (g_core->HeadlessMode()) {
|
||||
// NOTE: This length is currently milliseconds.
|
||||
headless_display_time_step_timer_ = event_loop()->NewTimer(
|
||||
1000 / 10, true, NewLambdaRunnable([this] { StepDisplayTime(); }));
|
||||
kAppModeMinHeadlessDisplayStep / 1000, true,
|
||||
NewLambdaRunnable([this] { StepDisplayTime(); }));
|
||||
}
|
||||
// Let our initial app-mode know it has become active.
|
||||
g_base->app_mode()->OnActivate();
|
||||
@ -267,7 +269,17 @@ void Logic::OnScreenSizeChange(float virtual_width, float virtual_height,
|
||||
void Logic::StepDisplayTime() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
UpdateDisplayTime();
|
||||
// We have two different modes of operation here. When running in headless
|
||||
// mode, display time is driven by upcoming events such as sim steps; we
|
||||
// basically want to sleep as long as we can and run steps exactly when
|
||||
// events occur. When running with a gui, our display-time is driven by
|
||||
// real draw times and is intended to keep frame intervals as visually
|
||||
// consistent and smooth looking as possible.
|
||||
if (g_core->HeadlessMode()) {
|
||||
UpdateDisplayTimeForHeadlessMode();
|
||||
} else {
|
||||
UpdateDisplayTimeForFrameDraw();
|
||||
}
|
||||
|
||||
// Give all our subsystems some update love.
|
||||
// Note: keep these in the same order as OnAppStart.
|
||||
@ -285,10 +297,86 @@ void Logic::StepDisplayTime() {
|
||||
|
||||
// Let's run display-timers *after* we step everything else so most things
|
||||
// they interact with will be in an up-to-date state.
|
||||
display_timers_->Run(g_core->GetAppTimeMillisecs());
|
||||
display_timers_->Run(display_time_microsecs_);
|
||||
|
||||
if (g_core->HeadlessMode()) {
|
||||
PostUpdateDisplayTimeForHeadlessMode();
|
||||
}
|
||||
}
|
||||
|
||||
void Logic::UpdateDisplayTime() {
|
||||
void Logic::OnAppModeChanged() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Kick our headless stepping into high gear; this will snap us out of
|
||||
// any long sleep we're currently in the middle of.
|
||||
if (g_core->HeadlessMode()) {
|
||||
if (debug_log_display_time_) {
|
||||
Log(LogLevel::kDebug,
|
||||
"Resetting headless display step timer due to app-mode change.");
|
||||
}
|
||||
assert(headless_display_time_step_timer_);
|
||||
// NOTE: This is currently milliseconds.
|
||||
headless_display_time_step_timer_->SetLength(kAppModeMinHeadlessDisplayStep
|
||||
/ 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void Logic::UpdateDisplayTimeForHeadlessMode() {
|
||||
assert(g_base->InLogicThread());
|
||||
// In this case we just keep display time synced up with app time; we don't
|
||||
// care about keeping the increments smooth or consistent.
|
||||
|
||||
// The one thing we *do* try to do, however, is keep our timer length
|
||||
// updated so that we fire exactly when the app mode has events scheduled
|
||||
// (or at least close enough so we can fudge it and tell them its that exact
|
||||
// time).
|
||||
|
||||
auto app_time_microsecs = g_core->GetAppTimeMicrosecs();
|
||||
|
||||
auto old_display_time_microsecs = display_time_microsecs_;
|
||||
display_time_microsecs_ = app_time_microsecs;
|
||||
display_time_increment_microsecs_ =
|
||||
display_time_microsecs_ - old_display_time_microsecs;
|
||||
|
||||
// In this path our float values are driven by our int ones.
|
||||
display_time_ = static_cast<double>(display_time_microsecs_) / 1000000.0;
|
||||
display_time_increment_ =
|
||||
static_cast<double>(display_time_increment_microsecs_) / 1000000.0;
|
||||
|
||||
if (debug_log_display_time_) {
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "stepping display-time at app-time %.4f",
|
||||
static_cast<double>(app_time_microsecs) / 1000000.0);
|
||||
Log(LogLevel::kDebug, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Logic::PostUpdateDisplayTimeForHeadlessMode() {
|
||||
assert(g_base->InLogicThread());
|
||||
// At this point we've stepped our app-mode, so let's ask it how
|
||||
// long we've got until the next event. We'll plug this into our
|
||||
// display-update timer so we can try to sleep until that point.
|
||||
auto headless_display_step_microsecs =
|
||||
std::max(std::min(g_base->app_mode()->GetHeadlessDisplayStep(),
|
||||
kAppModeMaxHeadlessDisplayStep),
|
||||
kAppModeMinHeadlessDisplayStep);
|
||||
|
||||
if (debug_log_display_time_) {
|
||||
auto sleepsecs =
|
||||
static_cast<double>(headless_display_step_microsecs) / 1000000.0;
|
||||
auto apptimesecs = g_core->GetAppTimeSeconds();
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"will try to sleep for %.4f at app-time %.4f (until %.4f)",
|
||||
sleepsecs, apptimesecs, apptimesecs + sleepsecs);
|
||||
Log(LogLevel::kDebug, buffer);
|
||||
}
|
||||
|
||||
auto sleep_millisecs = headless_display_step_microsecs / 1000;
|
||||
headless_display_time_step_timer_->SetLength(sleep_millisecs);
|
||||
}
|
||||
|
||||
void Logic::UpdateDisplayTimeForFrameDraw() {
|
||||
// Here we update our smoothed display-time-increment based on how fast
|
||||
// we are currently rendering frames. We want display-time to basically
|
||||
// be progressing at the same rate as app-time but in as constant
|
||||
@ -371,13 +459,14 @@ void Logic::UpdateDisplayTime() {
|
||||
avg /= count;
|
||||
double range = max - min;
|
||||
|
||||
// If our range of recent increment values is somewhat large relative to an
|
||||
// average value, things are probably chaotic so just use the current value
|
||||
// to respond quickly to changes. If things are more calm, use our nice
|
||||
// smoothed value.
|
||||
// If our range of recent increment values is somewhat large relative to
|
||||
// an average value, things are probably chaotic, so just use the
|
||||
// current value to respond quickly to changes. If things are more calm,
|
||||
// use our nice smoothed value.
|
||||
|
||||
// So in a case where we're seeing an average increment of 16ms, we snap
|
||||
// out of avg mode if there's more than 8ms between the longest and shortest
|
||||
// increments.
|
||||
// out of avg mode if there's more than 8ms between the longest and
|
||||
// shortest increments.
|
||||
double chaos = range / avg;
|
||||
bool use_avg = chaos < 0.5;
|
||||
auto used = use_avg ? avg : this_increment;
|
||||
@ -388,14 +477,14 @@ void Logic::UpdateDisplayTime() {
|
||||
// range.
|
||||
|
||||
// How far the smoothed increment value needs to get away from the final
|
||||
// value to actually start moving it.
|
||||
// Example: If our avg increment is 16.6ms (60fps), don't change our
|
||||
// increment until the 'used' value is more than 0.5ms (16.6 * 0.03) from it
|
||||
// in either direction.
|
||||
// Note: In practice I'm seeing that higher framerates
|
||||
// like 120 need buffers that are larger relative to avg to remain stable.
|
||||
// Though perhaps a bit of jitter is not noticeable at high frame rates;
|
||||
// just something to keep an eye on.
|
||||
// value to actually start moving it. Example: If our avg increment is
|
||||
// 16.6ms (60fps), don't change our increment until the 'used' value is
|
||||
// more than 0.5ms (16.6 * 0.03) from it in either direction.
|
||||
|
||||
// Note: In practice I'm seeing that higher framerates like 120 need
|
||||
// buffers that are larger relative to avg to remain stable. Though
|
||||
// perhaps a bit of jitter is not noticeable at high frame rates; just
|
||||
// something to keep an eye on.
|
||||
auto trail_buffer{avg * 0.03};
|
||||
|
||||
auto trailing_diff = used - display_time_increment_;
|
||||
@ -424,6 +513,11 @@ void Logic::UpdateDisplayTime() {
|
||||
}
|
||||
// Lastly, apply our updated increment value to our time.
|
||||
display_time_ += display_time_increment_;
|
||||
|
||||
// In this path, our integer values just follow our float ones.
|
||||
auto prev_microsecs = display_time_microsecs_;
|
||||
display_time_microsecs_ = static_cast<microsecs_t>(display_time_ * 1000000.0);
|
||||
display_time_increment_microsecs_ = display_time_microsecs_ - prev_microsecs;
|
||||
}
|
||||
|
||||
// Set up our sleeping based on what we're doing.
|
||||
@ -521,13 +615,13 @@ void Logic::SetAppTimerLength(int timer_id, millisecs_t length) {
|
||||
}
|
||||
}
|
||||
|
||||
auto Logic::NewDisplayTimer(millisecs_t length, bool repeat,
|
||||
auto Logic::NewDisplayTimer(microsecs_t length, bool repeat,
|
||||
const Object::Ref<Runnable>& runnable) -> int {
|
||||
// Display-Timers go into a timer-list that we exec explicitly when we
|
||||
// step display-time.
|
||||
assert(g_base->InLogicThread());
|
||||
int offset = 0;
|
||||
Timer* t = display_timers_->NewTimer(g_core->GetAppTimeMillisecs(), length,
|
||||
Timer* t = display_timers_->NewTimer(g_core->GetAppTimeMicrosecs(), length,
|
||||
offset, repeat ? -1 : 0, runnable);
|
||||
return t->id();
|
||||
}
|
||||
@ -537,7 +631,7 @@ void Logic::DeleteDisplayTimer(int timer_id) {
|
||||
display_timers_->DeleteTimer(timer_id);
|
||||
}
|
||||
|
||||
void Logic::SetDisplayTimerLength(int timer_id, millisecs_t length) {
|
||||
void Logic::SetDisplayTimerLength(int timer_id, microsecs_t length) {
|
||||
assert(g_base->InLogicThread());
|
||||
Timer* t = display_timers_->GetTimer(timer_id);
|
||||
if (t) {
|
||||
|
||||
@ -31,6 +31,8 @@ class Logic {
|
||||
void OnAppResume();
|
||||
void OnAppShutdown();
|
||||
|
||||
void OnAppModeChanged();
|
||||
|
||||
void ApplyAppConfig();
|
||||
void OnScreenSizeChange(float virtual_width, float virtual_height,
|
||||
float pixel_width, float pixel_height);
|
||||
@ -58,35 +60,48 @@ class Logic {
|
||||
void DeleteAppTimer(int timer_id);
|
||||
void SetAppTimerLength(int timer_id, millisecs_t length);
|
||||
|
||||
auto NewDisplayTimer(millisecs_t length, bool repeat,
|
||||
auto NewDisplayTimer(microsecs_t length, bool repeat,
|
||||
const Object::Ref<Runnable>& runnable) -> int;
|
||||
void DeleteDisplayTimer(int timer_id);
|
||||
void SetDisplayTimerLength(int timer_id, millisecs_t length);
|
||||
void SetDisplayTimerLength(int timer_id, microsecs_t length);
|
||||
|
||||
/// Get current display-time for the app (in seconds).
|
||||
/// Display-time is a seconds value that increments smoothly with
|
||||
/// frame draws.
|
||||
/// Get current display-time for the app in seconds.
|
||||
auto display_time() { return display_time_; }
|
||||
|
||||
/// Return current display-time increment (in seconds). This can shift with
|
||||
/// framerate changes but should remain mostly constant.
|
||||
/// Get current display-time for the app in microseconds.
|
||||
auto display_time_microsecs() { return display_time_microsecs_; }
|
||||
|
||||
/// Return current display-time increment in seconds.
|
||||
auto display_time_increment() -> double { return display_time_increment_; }
|
||||
|
||||
/// Return current display-time increment in microseconds.
|
||||
auto display_time_increment_microsecs() -> double {
|
||||
return display_time_increment_microsecs_;
|
||||
}
|
||||
|
||||
auto applied_app_config() const { return applied_app_config_; }
|
||||
|
||||
private:
|
||||
void UpdateDisplayTime();
|
||||
void UpdateDisplayTimeForFrameDraw();
|
||||
void UpdateDisplayTimeForHeadlessMode();
|
||||
void PostUpdateDisplayTimeForHeadlessMode();
|
||||
void CompleteAppBootstrapping();
|
||||
void ProcessPendingWork();
|
||||
void UpdatePendingWorkTimer();
|
||||
void StepDisplayTime();
|
||||
|
||||
double display_time_{};
|
||||
microsecs_t display_time_microsecs_{};
|
||||
double display_time_increment_{1.0 / 60.0};
|
||||
microsecs_t display_time_increment_microsecs_{1000000 / 60};
|
||||
|
||||
// GUI scheduling.
|
||||
double last_display_time_update_app_time_{-1.0};
|
||||
double recent_display_time_increments_[kDisplayTimeSampleCount]{};
|
||||
int recent_display_time_increments_index_{-1};
|
||||
|
||||
// Headless scheduling.
|
||||
|
||||
std::unique_ptr<TimerList> display_timers_;
|
||||
EventLoop* event_loop_{};
|
||||
Timer* process_pending_work_timer_{};
|
||||
|
||||
@ -194,8 +194,8 @@ auto BasePlatform::GetPublicDeviceUUID() -> std::string {
|
||||
// We used to plug version in directly here, but that caused uuids to
|
||||
// shuffle too rapidly during periods of rapid development. This
|
||||
// keeps it more constant.
|
||||
// __last_rand_uuid_component_shuffle_date__ 2022 12 17
|
||||
auto rand_uuid_component{"BMCJPHH0SC22KB0WVJ1RAYD68TPEXL58"};
|
||||
// __last_rand_uuid_component_shuffle_date__ 2023 6 15
|
||||
auto rand_uuid_component{"JVRWZ82D4WMBO110OA0IFJV7JKMQV8W3"};
|
||||
|
||||
inputs.emplace_back(rand_uuid_component);
|
||||
auto gil{Python::ScopedInterpreterLock()};
|
||||
|
||||
@ -103,7 +103,7 @@ auto PythonClassDisplayTimer::tp_new(PyTypeObject* type, PyObject* args,
|
||||
return nullptr;
|
||||
}
|
||||
self->timer_id_ = g_base->logic->NewDisplayTimer(
|
||||
static_cast<millisecs_t>(length * 1000.0), repeat,
|
||||
static_cast<microsecs_t>(length * 1000000.0), repeat,
|
||||
Object::New<Runnable, PythonContextCallRunnable>(call_obj));
|
||||
|
||||
self->have_timer_ = true;
|
||||
|
||||
@ -341,7 +341,7 @@ static auto PyAppTimer(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
if (length < 0) {
|
||||
throw Exception("Timer length cannot be < 0.", PyExcType::kValue);
|
||||
}
|
||||
g_base->logic->NewDisplayTimer(
|
||||
g_base->logic->NewAppTimer(
|
||||
static_cast<millisecs_t>(length * 1000.0), false,
|
||||
Object::New<Runnable, PythonContextCallRunnable>(call_obj));
|
||||
Py_RETURN_NONE;
|
||||
@ -376,9 +376,9 @@ static PyMethodDef PyAppTimerDef = {
|
||||
"##### Examples\n"
|
||||
"Print some stuff through time:\n"
|
||||
">>> babase.screenmessage('hello from now!')\n"
|
||||
">>> babase.apptimer(1.0, ba.Call(ba.screenmessage,\n"
|
||||
">>> babase.apptimer(1.0, babase.Call(babase.screenmessage,\n"
|
||||
" 'hello from the future!'))\n"
|
||||
">>> babase.apptimer(2.0, ba.Call(ba.screenmessage,\n"
|
||||
">>> babase.apptimer(2.0, babase.Call(babase.screenmessage,\n"
|
||||
"... 'hello from the future 2!'))\n",
|
||||
};
|
||||
|
||||
@ -434,8 +434,8 @@ static auto PyDisplayTimer(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
if (length < 0) {
|
||||
throw Exception("Timer length cannot be < 0.", PyExcType::kValue);
|
||||
}
|
||||
g_base->logic->NewAppTimer(
|
||||
static_cast<millisecs_t>(length * 1000.0), false,
|
||||
g_base->logic->NewDisplayTimer(
|
||||
static_cast<microsecs_t>(length * 1000000.0), false,
|
||||
Object::New<Runnable, PythonContextCallRunnable>(call_obj));
|
||||
Py_RETURN_NONE;
|
||||
BA_PYTHON_CATCH;
|
||||
@ -474,9 +474,9 @@ static PyMethodDef PyDisplayTimerDef = {
|
||||
"##### Examples\n"
|
||||
"Print some stuff through time:\n"
|
||||
">>> babase.screenmessage('hello from now!')\n"
|
||||
">>> babase.displaytimer(1.0, ba.Call(ba.screenmessage,\n"
|
||||
">>> babase.displaytimer(1.0, babase.Call(babase.screenmessage,\n"
|
||||
"... 'hello from the future!'))\n"
|
||||
">>> babase.displaytimer(2.0, ba.Call(ba.screenmessage,\n"
|
||||
">>> babase.displaytimer(2.0, babase.Call(babase.screenmessage,\n"
|
||||
"... 'hello from the future 2!'))\n",
|
||||
};
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ class AppTimer : public Object {
|
||||
timer_id_ = base::g_base->logic->NewAppTimer(length, repeat, runnable);
|
||||
}
|
||||
|
||||
void SetLength(uint32_t length) {
|
||||
void SetLength(millisecs_t length) {
|
||||
assert(g_base->InLogicThread());
|
||||
base::g_base->logic->SetAppTimerLength(timer_id_, length);
|
||||
}
|
||||
|
||||
@ -401,7 +401,7 @@ void FlagNode::Step() {
|
||||
dBodyID b = body_->body();
|
||||
assert(b);
|
||||
|
||||
if (g_core->HeadlessMode()) {
|
||||
if (!g_core->HeadlessMode()) {
|
||||
dVector3 p;
|
||||
FullShadowSet* full_shadows = full_shadow_set_.Get();
|
||||
if (full_shadows) {
|
||||
|
||||
@ -578,6 +578,14 @@ void HostSession::Update(int time_advance_millisecs, double time_advance) {
|
||||
assert(test_ref.Exists());
|
||||
}
|
||||
|
||||
auto HostSession::TimeToNextEvent() -> std::optional<microsecs_t> {
|
||||
if (base_timers_.Empty()) {
|
||||
return {};
|
||||
}
|
||||
auto to_next_ms = base_timers_.TimeToNextExpire(base_time_millisecs_);
|
||||
return to_next_ms * 1000; // to microsecs.
|
||||
}
|
||||
|
||||
HostSession::~HostSession() {
|
||||
assert(g_base->InLogicThread());
|
||||
try {
|
||||
|
||||
@ -103,6 +103,7 @@ class HostSession : public Session {
|
||||
auto GetUnusedPlayerName(Player* p, const std::string& base_name)
|
||||
-> std::string;
|
||||
auto ContextAllowsDefaultTimerTypes() -> bool override;
|
||||
auto TimeToNextEvent() -> std::optional<microsecs_t> override;
|
||||
|
||||
private:
|
||||
void StepScene();
|
||||
|
||||
@ -408,6 +408,25 @@ auto SceneV1AppMode::GetPartySize() const -> int {
|
||||
return cJSON_GetArraySize(game_roster_);
|
||||
}
|
||||
|
||||
auto SceneV1AppMode::GetHeadlessDisplayStep() -> microsecs_t {
|
||||
std::optional<microsecs_t> min_time_to_next;
|
||||
for (auto&& i : sessions_) {
|
||||
if (!i.Exists()) {
|
||||
continue;
|
||||
}
|
||||
auto this_time_to_next = i->TimeToNextEvent();
|
||||
if (this_time_to_next.has_value()) {
|
||||
if (!min_time_to_next.has_value()) {
|
||||
min_time_to_next = *this_time_to_next;
|
||||
} else {
|
||||
min_time_to_next = std::min(*min_time_to_next, *this_time_to_next);
|
||||
}
|
||||
}
|
||||
}
|
||||
return min_time_to_next.has_value() ? *min_time_to_next
|
||||
: base::kAppModeMaxHeadlessDisplayStep;
|
||||
}
|
||||
|
||||
void SceneV1AppMode::StepDisplayTime() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
@ -426,7 +445,8 @@ void SceneV1AppMode::StepDisplayTime() {
|
||||
// each time).
|
||||
millisecs_t legacy_display_time_millisecs_inc;
|
||||
if (legacy_display_time_millisecs_prev_ < 0) {
|
||||
// Convert directly *only* the first time when we don't have prev available.
|
||||
// Convert directly *only* the first time when we don't have prev
|
||||
// available.
|
||||
legacy_display_time_millisecs_inc = static_cast<millisecs_t>(
|
||||
g_base->logic->display_time_increment() * 1000.0);
|
||||
|
||||
@ -677,8 +697,8 @@ void SceneV1AppMode::UpdateKickVote() {
|
||||
1, 1, 0);
|
||||
kick_vote_in_progress_ = false;
|
||||
|
||||
// Disallow kicking for a while for everyone.. but ESPECIALLY so for the guy
|
||||
// who launched the failed vote.
|
||||
// Disallow kicking for a while for everyone.. but ESPECIALLY so for the
|
||||
// guy who launched the failed vote.
|
||||
for (ConnectionToClient* client :
|
||||
connections()->GetConnectionsToClients()) {
|
||||
millisecs_t delay = kKickVoteFailRetryDelay;
|
||||
|
||||
@ -182,6 +182,7 @@ class SceneV1AppMode : public base::AppMode {
|
||||
auto buffer_time() const { return buffer_time_; }
|
||||
void set_buffer_time(int val) { buffer_time_ = val; }
|
||||
void OnActivate() override;
|
||||
auto GetHeadlessDisplayStep() -> microsecs_t override;
|
||||
|
||||
private:
|
||||
void PruneScanResults();
|
||||
|
||||
@ -19,6 +19,12 @@ Session::~Session() { g_core->session_count--; }
|
||||
|
||||
void Session::Update(int time_advance_millisecs, double time_advance) {}
|
||||
|
||||
auto Session::TimeToNextEvent() -> std::optional<microsecs_t> {
|
||||
BA_LOG_ONCE(LogLevel::kError,
|
||||
"Session::TimeToNextEvent() being called; should not happen.");
|
||||
return 5000000;
|
||||
}
|
||||
|
||||
auto Session::GetForegroundContext() -> base::ContextRef { return {}; }
|
||||
|
||||
void Session::Draw(base::FrameDef*) {}
|
||||
|
||||
@ -19,6 +19,9 @@ class Session : public SceneV1Context {
|
||||
/// a modern seconds advance.
|
||||
virtual void Update(int time_advance_millisecs, double time_advance);
|
||||
|
||||
/// Note: this should be returned in microsecs.
|
||||
virtual auto TimeToNextEvent() -> std::optional<microsecs_t>;
|
||||
|
||||
// If this returns false, the screen will be cleared as part of rendering.
|
||||
virtual auto DoesFillScreen() const -> bool = 0;
|
||||
|
||||
|
||||
@ -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 = 21107;
|
||||
const int kEngineBuildNumber = 21108;
|
||||
const char* kEngineVersion = "1.7.20";
|
||||
|
||||
auto MonolithicMain(const core::CoreConfig& core_config) -> int {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user