mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-05 15:03:33 +08:00
Finished wiring up clean_exit_minutes, unclean_exit_minutes, and idle_exit_minutes in server configs
This commit is contained in:
parent
5125b005c7
commit
5f909d0b91
@ -3932,24 +3932,24 @@
|
|||||||
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
|
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
|
||||||
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
|
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
|
||||||
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
|
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
|
||||||
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/e1/70ff36467d1875af3e0e38da754c",
|
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/46/08/c5c18d49571ed38eebf9596704c5",
|
||||||
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5c/83/e1f9e8db08f24a1d0b08958b9e09",
|
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/2d/9858a8c8735debb23fe24e2efe4b",
|
||||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/ae/bc2f695f28eb3405415ea11c8083",
|
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/e9/7600ca36570a7dcf5af9647a2e21",
|
||||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cb/ab/076371cc80fb408dfe2cbd4da8b0",
|
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/e4/ec93fdb61177cda5ff992506ac17",
|
||||||
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/70/203ffd8485f6e3b5432c70b556b3",
|
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/df/fb/05e0398c5bbe64fad410ea375356",
|
||||||
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f5/51/9b37b71adfaa2d5ca706bc168b2f",
|
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/25/eb/ea4a1b0694ad2cf60352defc69af",
|
||||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5d/87/089a0508c2876e6090f337a6a1c6",
|
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/50/422233084047a81e036c132bde39",
|
||||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fe/49/c33812c8596e946c4b7ff4a70176",
|
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/4d/3447d7b2f7a8bc64ca7bdd6536f1",
|
||||||
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/65/c0/cede9d63e3c3fd3148b1d25ba62f",
|
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/38/35/fa7173464f9527e374a0ce94b3bd",
|
||||||
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4b/e0/26d2281f316b0f704a6a404b030b",
|
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cc/b1/a94d7f123b22ed23e00f40e579d1",
|
||||||
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a7/b8/988ab1f0d337516c034301ce219a",
|
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/53/4a/02860b49bda65c53123447c69b90",
|
||||||
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/69/80/9068d8f99a060c625abee7b49184",
|
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fe/e2/1c603aed8baf632d28226b2031e6",
|
||||||
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4f/4c/8590730e5d1cdae456c1b734a2a1",
|
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/54/a1/e5a2906b6bd18229f21f5a5d0876",
|
||||||
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/44/e5/d1c3162e114e51a5b5b826c2ec7c",
|
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b9/e7/ac87044e0eac75551bcacdf2e41d",
|
||||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ee/21/8fab3da6b974cf323024d076b609",
|
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/18/c2/3a457694a20c7dc22eb0d5cb67fc",
|
||||||
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/20/5d/881676243c5f44bdca677497b4d4",
|
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3a/0c/96264568710c8e6a84af77a4f0d9",
|
||||||
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/90/a3/e265c556587921cdfd8c753b592f",
|
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/51/96/56697bf4a444ebe66b28c616e279",
|
||||||
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/5e/80ac1a7a4a75de8869755aa7cbc1",
|
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2c/5b/303bfdb73180faf55ba78fa2bcc8",
|
||||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b0/4a/2144949c2cb6c3ef7d99c4409bfb",
|
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/09/83/ecaaf27743299eb80fd6ae704f23",
|
||||||
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f8/ce/078603417240c7f8a7f067d55a6f"
|
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/22/9f/c6686359ba318f695a0a0900f2c2"
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
### 1.5.29 (20246)
|
### 1.5.29 (20246)
|
||||||
- Exposed ba method/class initing in public C++ layer.
|
- Exposed ba method/class initing in public C++ layer.
|
||||||
- The 'restart' and 'shutdown' commands in the server script now default to immediate=True
|
- The 'restart' and 'shutdown' commands in the server script now default to immediate=True
|
||||||
|
- Wired up 'clean_exit_minutes', 'unclean_exit_minutes', and 'idle_exit_minutes' options in the server config
|
||||||
|
|
||||||
### 1.5.28 (20239)
|
### 1.5.28 (20239)
|
||||||
- Simplified ba.enum_by_value()
|
- Simplified ba.enum_by_value()
|
||||||
|
|||||||
@ -2079,7 +2079,7 @@ def get_idle_time() -> int:
|
|||||||
|
|
||||||
(internal)
|
(internal)
|
||||||
|
|
||||||
Returns the amount of time since any game input has been processed
|
Returns the amount of time since any game input has been received.
|
||||||
"""
|
"""
|
||||||
return int()
|
return int()
|
||||||
|
|
||||||
|
|||||||
@ -124,7 +124,7 @@ class ServerManagerApp:
|
|||||||
|
|
||||||
# Python will handle SIGINT for us (as KeyboardInterrupt) but we
|
# Python will handle SIGINT for us (as KeyboardInterrupt) but we
|
||||||
# need to register a SIGTERM handler so we have a chance to clean
|
# need to register a SIGTERM handler so we have a chance to clean
|
||||||
# up our child-process when someone tells us to die. (and avoid
|
# up our subprocess when someone tells us to die. (and avoid
|
||||||
# zombie processes)
|
# zombie processes)
|
||||||
signal.signal(signal.SIGTERM, self._handle_term_signal)
|
signal.signal(signal.SIGTERM, self._handle_term_signal)
|
||||||
|
|
||||||
@ -150,12 +150,17 @@ class ServerManagerApp:
|
|||||||
print(f'{Clr.SRED}Unexpected interpreter exception:'
|
print(f'{Clr.SRED}Unexpected interpreter exception:'
|
||||||
f' {exc} ({type(exc)}){Clr.RST}')
|
f' {exc} ({type(exc)}){Clr.RST}')
|
||||||
|
|
||||||
|
print(f'{Clr.CYN}Server manager shutting down...{Clr.RST}')
|
||||||
|
|
||||||
|
if self._subprocess_thread.is_alive():
|
||||||
|
print(f'{Clr.CYN}Waiting for subprocess exit...{Clr.RST}')
|
||||||
|
|
||||||
# Mark ourselves as shutting down and wait for the process to wrap up.
|
# Mark ourselves as shutting down and wait for the process to wrap up.
|
||||||
self._done = True
|
self._done = True
|
||||||
self._subprocess_thread.join()
|
self._subprocess_thread.join()
|
||||||
|
|
||||||
def cmd(self, statement: str) -> None:
|
def cmd(self, statement: str) -> None:
|
||||||
"""Exec a Python command on the current running server child-process.
|
"""Exec a Python command on the current running server subprocess.
|
||||||
|
|
||||||
Note that commands are executed asynchronously and no status or
|
Note that commands are executed asynchronously and no status or
|
||||||
return value is accessible from this manager app.
|
return value is accessible from this manager app.
|
||||||
@ -227,7 +232,7 @@ class ServerManagerApp:
|
|||||||
KickCommand(client_id=client_id, ban_time=ban_time))
|
KickCommand(client_id=client_id, ban_time=ban_time))
|
||||||
|
|
||||||
def restart(self, immediate: bool = True) -> None:
|
def restart(self, immediate: bool = True) -> None:
|
||||||
"""Restart the server child-process.
|
"""Restart the server subprocess.
|
||||||
|
|
||||||
This can be necessary for some config changes to take effect.
|
This can be necessary for some config changes to take effect.
|
||||||
By default, the server will exit immediately. If 'immediate' is passed
|
By default, the server will exit immediately. If 'immediate' is passed
|
||||||
@ -246,7 +251,7 @@ class ServerManagerApp:
|
|||||||
IMMEDIATE_SHUTDOWN_TIME_LIMIT)
|
IMMEDIATE_SHUTDOWN_TIME_LIMIT)
|
||||||
|
|
||||||
def shutdown(self, immediate: bool = True) -> None:
|
def shutdown(self, immediate: bool = True) -> None:
|
||||||
"""Shut down the server child-process and exit the wrapper
|
"""Shut down the server subprocess and exit the wrapper
|
||||||
|
|
||||||
By default, the server will exit immediately. If 'immediate' is passed
|
By default, the server will exit immediately. If 'immediate' is passed
|
||||||
as False, however, the server will instead exit at the next clean
|
as False, however, the server will instead exit at the next clean
|
||||||
@ -256,7 +261,8 @@ class ServerManagerApp:
|
|||||||
self._enqueue_server_command(
|
self._enqueue_server_command(
|
||||||
ShutdownCommand(reason=ShutdownReason.NONE, immediate=immediate))
|
ShutdownCommand(reason=ShutdownReason.NONE, immediate=immediate))
|
||||||
|
|
||||||
# So we know to bail completely once this subprocess completes.
|
# An explicit shutdown means we know to bail completely once this
|
||||||
|
# subprocess completes.
|
||||||
self._wrapper_shutdown_desired = True
|
self._wrapper_shutdown_desired = True
|
||||||
|
|
||||||
# If we're asking for an immediate shutdown but don't get one within
|
# If we're asking for an immediate shutdown but don't get one within
|
||||||
@ -304,7 +310,7 @@ class ServerManagerApp:
|
|||||||
raise SystemExit()
|
raise SystemExit()
|
||||||
|
|
||||||
def _run_server_cycle(self) -> None:
|
def _run_server_cycle(self) -> None:
|
||||||
"""Spin up the server child-process and run it until exit."""
|
"""Spin up the server subprocess and run it until exit."""
|
||||||
|
|
||||||
self._prep_subprocess_environment()
|
self._prep_subprocess_environment()
|
||||||
|
|
||||||
@ -317,7 +323,7 @@ class ServerManagerApp:
|
|||||||
# slight behavior tweaks. Hmm; should this be an argument instead?
|
# slight behavior tweaks. Hmm; should this be an argument instead?
|
||||||
os.environ['BA_SERVER_WRAPPER_MANAGED'] = '1'
|
os.environ['BA_SERVER_WRAPPER_MANAGED'] = '1'
|
||||||
|
|
||||||
print(f'{Clr.CYN}Launching server child-process...{Clr.RST}')
|
print(f'{Clr.CYN}Launching server subprocess...{Clr.RST}')
|
||||||
binary_name = ('ballisticacore_headless.exe'
|
binary_name = ('ballisticacore_headless.exe'
|
||||||
if os.name == 'nt' else './ballisticacore_headless')
|
if os.name == 'nt' else './ballisticacore_headless')
|
||||||
self._subprocess = subprocess.Popen(
|
self._subprocess = subprocess.Popen(
|
||||||
@ -332,14 +338,17 @@ class ServerManagerApp:
|
|||||||
finally:
|
finally:
|
||||||
self._kill_subprocess()
|
self._kill_subprocess()
|
||||||
|
|
||||||
|
# If we want to die completely after this subprocess has ended,
|
||||||
|
# tell the main thread to die.
|
||||||
if self._wrapper_shutdown_desired:
|
if self._wrapper_shutdown_desired:
|
||||||
# Note: need to only do this if main thread is still in the
|
|
||||||
# interpreter; otherwise it seems this can lead to deadlock.
|
# Only do this if the main thread is not already waiting for
|
||||||
|
# us to die; otherwise it can lead to deadlock.
|
||||||
if not self._done:
|
if not self._done:
|
||||||
self._done = True
|
self._done = True
|
||||||
|
|
||||||
# Our main thread is still be blocked in its prompt or
|
# This should break the main thread out of its blocking
|
||||||
# whatnot; let it know it should die.
|
# interpreter call.
|
||||||
os.kill(os.getpid(), signal.SIGTERM)
|
os.kill(os.getpid(), signal.SIGTERM)
|
||||||
|
|
||||||
def _prep_subprocess_environment(self) -> None:
|
def _prep_subprocess_environment(self) -> None:
|
||||||
@ -356,6 +365,7 @@ class ServerManagerApp:
|
|||||||
bincfg['Port'] = self._config.port
|
bincfg['Port'] = self._config.port
|
||||||
bincfg['Auto Balance Teams'] = self._config.auto_balance_teams
|
bincfg['Auto Balance Teams'] = self._config.auto_balance_teams
|
||||||
bincfg['Show Tutorial'] = False
|
bincfg['Show Tutorial'] = False
|
||||||
|
bincfg['Idle Exit Minutes'] = self._config.idle_exit_minutes
|
||||||
with open('dist/ba_root/config.json', 'w') as outfile:
|
with open('dist/ba_root/config.json', 'w') as outfile:
|
||||||
outfile.write(json.dumps(bincfg))
|
outfile.write(json.dumps(bincfg))
|
||||||
|
|
||||||
@ -384,11 +394,9 @@ class ServerManagerApp:
|
|||||||
self._subprocess.stdin.flush()
|
self._subprocess.stdin.flush()
|
||||||
|
|
||||||
def _run_subprocess_until_exit(self) -> None:
|
def _run_subprocess_until_exit(self) -> None:
|
||||||
# pylint: disable=too-many-branches
|
|
||||||
assert current_thread() is self._subprocess_thread
|
assert current_thread() is self._subprocess_thread
|
||||||
assert self._subprocess is not None
|
assert self._subprocess is not None
|
||||||
assert self._subprocess.stdin is not None
|
assert self._subprocess.stdin is not None
|
||||||
assert self._subprocess_launch_time is not None
|
|
||||||
|
|
||||||
# Send the initial server config which should kick things off.
|
# Send the initial server config which should kick things off.
|
||||||
# (but make sure its values are still valid first)
|
# (but make sure its values are still valid first)
|
||||||
@ -414,35 +422,7 @@ class ServerManagerApp:
|
|||||||
self._subprocess_commands = []
|
self._subprocess_commands = []
|
||||||
|
|
||||||
# Request restarts/shut-downs for various reasons.
|
# Request restarts/shut-downs for various reasons.
|
||||||
sincelaunch = time.time() - self._subprocess_launch_time
|
self._request_shutdowns_or_restarts()
|
||||||
if (self._restart_minutes is not None and sincelaunch >
|
|
||||||
(self._restart_minutes * 60.0)
|
|
||||||
and not self._subprocess_sent_auto_restart):
|
|
||||||
print(f'{Clr.CYN}restart_minutes ({self._restart_minutes})'
|
|
||||||
f' elapsed; requesting child-process'
|
|
||||||
f' soft restart...{Clr.RST}')
|
|
||||||
self.restart()
|
|
||||||
self._subprocess_sent_auto_restart = True
|
|
||||||
if self._config.clean_exit_minutes is not None:
|
|
||||||
elapsed = (time.time() - self._launch_time) / 60.0
|
|
||||||
if (elapsed > self._config.clean_exit_minutes
|
|
||||||
and not self._subprocess_sent_clean_exit):
|
|
||||||
print(f'{Clr.CYN}clean_exit_minutes'
|
|
||||||
f' ({self._config.clean_exit_minutes})'
|
|
||||||
f' elapsed; requesting child-process'
|
|
||||||
f' shutdown...{Clr.RST}')
|
|
||||||
self.shutdown(immediate=False)
|
|
||||||
self._subprocess_sent_clean_exit = True
|
|
||||||
if self._config.unclean_exit_minutes is not None:
|
|
||||||
elapsed = (time.time() - self._launch_time) / 60.0
|
|
||||||
if (elapsed > self._config.unclean_exit_minutes
|
|
||||||
and not self._subprocess_sent_unclean_exit):
|
|
||||||
print(f'{Clr.CYN}unclean_exit_minutes'
|
|
||||||
f' ({self._config.unclean_exit_minutes})'
|
|
||||||
f' elapsed; requesting child-process'
|
|
||||||
f' shutdown...{Clr.RST}')
|
|
||||||
self.shutdown(immediate=True)
|
|
||||||
self._subprocess_sent_unclean_exit = True
|
|
||||||
|
|
||||||
# If they want to force-kill our subprocess, simply exit this
|
# If they want to force-kill our subprocess, simply exit this
|
||||||
# loop; the cleanup code will kill the process.
|
# loop; the cleanup code will kill the process.
|
||||||
@ -457,17 +437,60 @@ class ServerManagerApp:
|
|||||||
if code == 0:
|
if code == 0:
|
||||||
clr = Clr.CYN
|
clr = Clr.CYN
|
||||||
slp = 0.0
|
slp = 0.0
|
||||||
|
desc = ''
|
||||||
|
elif code == 154:
|
||||||
|
clr = Clr.CYN
|
||||||
|
slp = 0.0
|
||||||
|
desc = ' (idle_exit_minutes reached)'
|
||||||
|
self._wrapper_shutdown_desired = True
|
||||||
else:
|
else:
|
||||||
clr = Clr.SRED
|
clr = Clr.SRED
|
||||||
slp = 5.0 # Avoid super fast death loops.
|
slp = 5.0 # Avoid super fast death loops.
|
||||||
print(f'{clr}Server child-process exited'
|
desc = ''
|
||||||
f' with code {code}.{Clr.RST}')
|
print(f'{clr}Server subprocess exited'
|
||||||
|
f' with code {code}{desc}.{Clr.RST}')
|
||||||
self._reset_subprocess_vars()
|
self._reset_subprocess_vars()
|
||||||
time.sleep(slp)
|
time.sleep(slp)
|
||||||
break
|
break
|
||||||
|
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
|
|
||||||
|
def _request_shutdowns_or_restarts(self) -> None:
|
||||||
|
assert current_thread() is self._subprocess_thread
|
||||||
|
assert self._subprocess_launch_time is not None
|
||||||
|
sincelaunch = time.time() - self._subprocess_launch_time
|
||||||
|
|
||||||
|
if (self._restart_minutes is not None and sincelaunch >
|
||||||
|
(self._restart_minutes * 60.0)
|
||||||
|
and not self._subprocess_sent_auto_restart):
|
||||||
|
print(f'{Clr.CYN}restart_minutes ({self._restart_minutes})'
|
||||||
|
f' elapsed; requesting subprocess'
|
||||||
|
f' soft restart...{Clr.RST}')
|
||||||
|
self.restart()
|
||||||
|
self._subprocess_sent_auto_restart = True
|
||||||
|
|
||||||
|
if self._config.clean_exit_minutes is not None:
|
||||||
|
elapsed = (time.time() - self._launch_time) / 60.0
|
||||||
|
if (elapsed > self._config.clean_exit_minutes
|
||||||
|
and not self._subprocess_sent_clean_exit):
|
||||||
|
print(f'{Clr.CYN}clean_exit_minutes'
|
||||||
|
f' ({self._config.clean_exit_minutes})'
|
||||||
|
f' elapsed; requesting subprocess'
|
||||||
|
f' shutdown...{Clr.RST}')
|
||||||
|
self.shutdown(immediate=False)
|
||||||
|
self._subprocess_sent_clean_exit = True
|
||||||
|
|
||||||
|
if self._config.unclean_exit_minutes is not None:
|
||||||
|
elapsed = (time.time() - self._launch_time) / 60.0
|
||||||
|
if (elapsed > self._config.unclean_exit_minutes
|
||||||
|
and not self._subprocess_sent_unclean_exit):
|
||||||
|
print(f'{Clr.CYN}unclean_exit_minutes'
|
||||||
|
f' ({self._config.unclean_exit_minutes})'
|
||||||
|
f' elapsed; requesting subprocess'
|
||||||
|
f' shutdown...{Clr.RST}')
|
||||||
|
self.shutdown(immediate=True)
|
||||||
|
self._subprocess_sent_unclean_exit = True
|
||||||
|
|
||||||
def _reset_subprocess_vars(self) -> None:
|
def _reset_subprocess_vars(self) -> None:
|
||||||
self._subprocess = None
|
self._subprocess = None
|
||||||
self._subprocess_launch_time = None
|
self._subprocess_launch_time = None
|
||||||
@ -477,12 +500,12 @@ class ServerManagerApp:
|
|||||||
self._subprocess_force_kill_time = None
|
self._subprocess_force_kill_time = None
|
||||||
|
|
||||||
def _kill_subprocess(self) -> None:
|
def _kill_subprocess(self) -> None:
|
||||||
"""End the server process if it still exists."""
|
"""End the server subprocess if it still exists."""
|
||||||
assert current_thread() is self._subprocess_thread
|
assert current_thread() is self._subprocess_thread
|
||||||
if self._subprocess is None:
|
if self._subprocess is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
print(f'{Clr.CYN}Stopping server process...{Clr.RST}')
|
print(f'{Clr.CYN}Stopping subprocess...{Clr.RST}')
|
||||||
|
|
||||||
# First, ask it nicely to die and give it a moment.
|
# First, ask it nicely to die and give it a moment.
|
||||||
# If that doesn't work, bring down the hammer.
|
# If that doesn't work, bring down the hammer.
|
||||||
@ -492,7 +515,7 @@ class ServerManagerApp:
|
|||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
self._subprocess.kill()
|
self._subprocess.kill()
|
||||||
self._reset_subprocess_vars()
|
self._reset_subprocess_vars()
|
||||||
print(f'{Clr.CYN}Server process stopped.{Clr.RST}')
|
print(f'{Clr.CYN}Subprocess stopped.{Clr.RST}')
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||||
<h4><em>last updated on 2020-11-12 for Ballistica version 1.5.29 build 20248</em></h4>
|
<h4><em>last updated on 2020-11-15 for Ballistica version 1.5.29 build 20254</em></h4>
|
||||||
<p>This page documents the Python classes and functions in the 'ba' module,
|
<p>This page documents the Python classes and functions in the 'ba' module,
|
||||||
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@ -16,6 +16,10 @@ auto AppConfig::Entry::FloatValue() const -> float {
|
|||||||
throw Exception("not a float entry");
|
throw Exception("not a float entry");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto AppConfig::Entry::OptionalFloatValue() const -> std::optional<float> {
|
||||||
|
throw Exception("not an optional float entry");
|
||||||
|
}
|
||||||
|
|
||||||
auto AppConfig::Entry::StringValue() const -> std::string {
|
auto AppConfig::Entry::StringValue() const -> std::string {
|
||||||
throw Exception("not a string entry");
|
throw Exception("not a string entry");
|
||||||
}
|
}
|
||||||
@ -32,6 +36,11 @@ auto AppConfig::Entry::DefaultFloatValue() const -> float {
|
|||||||
throw Exception("not a float entry");
|
throw Exception("not a float entry");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto AppConfig::Entry::DefaultOptionalFloatValue() const
|
||||||
|
-> std::optional<float> {
|
||||||
|
throw Exception("not an optional float entry");
|
||||||
|
}
|
||||||
|
|
||||||
auto AppConfig::Entry::DefaultStringValue() const -> std::string {
|
auto AppConfig::Entry::DefaultStringValue() const -> std::string {
|
||||||
throw Exception("not a string entry");
|
throw Exception("not a string entry");
|
||||||
}
|
}
|
||||||
@ -78,6 +87,26 @@ class AppConfig::FloatEntry : public AppConfig::Entry {
|
|||||||
float default_value_{};
|
float default_value_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AppConfig::OptionalFloatEntry : public AppConfig::Entry {
|
||||||
|
public:
|
||||||
|
OptionalFloatEntry() = default;
|
||||||
|
OptionalFloatEntry(const char* name, std::optional<float> default_value)
|
||||||
|
: Entry(name), default_value_(default_value) {}
|
||||||
|
auto GetType() const -> Type override { return Type::kOptionalFloat; }
|
||||||
|
auto Resolve() const -> std::optional<float> {
|
||||||
|
return g_python->GetRawConfigValue(name().c_str(), default_value_);
|
||||||
|
}
|
||||||
|
auto OptionalFloatValue() const -> std::optional<float> override {
|
||||||
|
return Resolve();
|
||||||
|
}
|
||||||
|
auto DefaultOptionalFloatValue() const -> std::optional<float> override {
|
||||||
|
return default_value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<float> default_value_{};
|
||||||
|
};
|
||||||
|
|
||||||
class AppConfig::IntEntry : public AppConfig::Entry {
|
class AppConfig::IntEntry : public AppConfig::Entry {
|
||||||
public:
|
public:
|
||||||
IntEntry() = default;
|
IntEntry() = default;
|
||||||
@ -157,6 +186,9 @@ void AppConfig::SetupEntries() {
|
|||||||
float_entries_[FloatID::kGoogleVRRenderTargetScale] =
|
float_entries_[FloatID::kGoogleVRRenderTargetScale] =
|
||||||
FloatEntry("GVR Render Target Scale", gvrrts_default);
|
FloatEntry("GVR Render Target Scale", gvrrts_default);
|
||||||
|
|
||||||
|
optional_float_entries_[OptionalFloatID::kIdleExitMinutes] =
|
||||||
|
OptionalFloatEntry("Idle Exit Minutes", std::optional<float>());
|
||||||
|
|
||||||
string_entries_[StringID::kResolutionAndroid] =
|
string_entries_[StringID::kResolutionAndroid] =
|
||||||
StringEntry("Resolution (Android)", "Auto");
|
StringEntry("Resolution (Android)", "Auto");
|
||||||
string_entries_[StringID::kTouchActionControlType] =
|
string_entries_[StringID::kTouchActionControlType] =
|
||||||
@ -220,6 +252,14 @@ auto AppConfig::Resolve(FloatID id) -> float {
|
|||||||
return i->second.Resolve();
|
return i->second.Resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto AppConfig::Resolve(OptionalFloatID id) -> std::optional<float> {
|
||||||
|
auto i = optional_float_entries_.find(id);
|
||||||
|
if (i == optional_float_entries_.end()) {
|
||||||
|
throw Exception("Invalid config entry");
|
||||||
|
}
|
||||||
|
return i->second.Resolve();
|
||||||
|
}
|
||||||
|
|
||||||
auto AppConfig::Resolve(StringID id) -> std::string {
|
auto AppConfig::Resolve(StringID id) -> std::string {
|
||||||
auto i = string_entries_.find(id);
|
auto i = string_entries_.find(id);
|
||||||
if (i == string_entries_.end()) {
|
if (i == string_entries_.end()) {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -30,6 +31,11 @@ class AppConfig {
|
|||||||
kLast // Sentinel.
|
kLast // Sentinel.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class OptionalFloatID {
|
||||||
|
kIdleExitMinutes,
|
||||||
|
kLast // Sentinel.
|
||||||
|
};
|
||||||
|
|
||||||
enum class StringID {
|
enum class StringID {
|
||||||
kResolutionAndroid,
|
kResolutionAndroid,
|
||||||
kTouchActionControlType,
|
kTouchActionControlType,
|
||||||
@ -68,16 +74,18 @@ class AppConfig {
|
|||||||
|
|
||||||
class Entry {
|
class Entry {
|
||||||
public:
|
public:
|
||||||
enum class Type { kString, kInt, kFloat, kBool };
|
enum class Type { kString, kInt, kFloat, kOptionalFloat, kBool };
|
||||||
Entry() = default;
|
Entry() = default;
|
||||||
explicit Entry(const char* name) : name_(name) {}
|
explicit Entry(const char* name) : name_(name) {}
|
||||||
virtual auto GetType() const -> Type = 0;
|
virtual auto GetType() const -> Type = 0;
|
||||||
auto name() const -> const std::string& { return name_; }
|
auto name() const -> const std::string& { return name_; }
|
||||||
virtual auto FloatValue() const -> float;
|
virtual auto FloatValue() const -> float;
|
||||||
|
virtual auto OptionalFloatValue() const -> std::optional<float>;
|
||||||
virtual auto StringValue() const -> std::string;
|
virtual auto StringValue() const -> std::string;
|
||||||
virtual auto IntValue() const -> int;
|
virtual auto IntValue() const -> int;
|
||||||
virtual auto BoolValue() const -> bool;
|
virtual auto BoolValue() const -> bool;
|
||||||
virtual auto DefaultFloatValue() const -> float;
|
virtual auto DefaultFloatValue() const -> float;
|
||||||
|
virtual auto DefaultOptionalFloatValue() const -> std::optional<float>;
|
||||||
virtual auto DefaultStringValue() const -> std::string;
|
virtual auto DefaultStringValue() const -> std::string;
|
||||||
virtual auto DefaultIntValue() const -> int;
|
virtual auto DefaultIntValue() const -> int;
|
||||||
virtual auto DefaultBoolValue() const -> bool;
|
virtual auto DefaultBoolValue() const -> bool;
|
||||||
@ -91,6 +99,7 @@ class AppConfig {
|
|||||||
|
|
||||||
// Given specific ids, returns resolved values (fastest access).
|
// Given specific ids, returns resolved values (fastest access).
|
||||||
auto Resolve(FloatID id) -> float;
|
auto Resolve(FloatID id) -> float;
|
||||||
|
auto Resolve(OptionalFloatID id) -> std::optional<float>;
|
||||||
auto Resolve(StringID id) -> std::string;
|
auto Resolve(StringID id) -> std::string;
|
||||||
auto Resolve(IntID id) -> int;
|
auto Resolve(IntID id) -> int;
|
||||||
auto Resolve(BoolID id) -> bool;
|
auto Resolve(BoolID id) -> bool;
|
||||||
@ -113,6 +122,7 @@ class AppConfig {
|
|||||||
private:
|
private:
|
||||||
class StringEntry;
|
class StringEntry;
|
||||||
class FloatEntry;
|
class FloatEntry;
|
||||||
|
class OptionalFloatEntry;
|
||||||
class IntEntry;
|
class IntEntry;
|
||||||
class BoolEntry;
|
class BoolEntry;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -120,6 +130,7 @@ class AppConfig {
|
|||||||
void SetupEntries();
|
void SetupEntries();
|
||||||
std::map<std::string, const Entry*> entries_by_name_;
|
std::map<std::string, const Entry*> entries_by_name_;
|
||||||
std::map<FloatID, FloatEntry> float_entries_;
|
std::map<FloatID, FloatEntry> float_entries_;
|
||||||
|
std::map<OptionalFloatID, OptionalFloatEntry> optional_float_entries_;
|
||||||
std::map<IntID, IntEntry> int_entries_;
|
std::map<IntID, IntEntry> int_entries_;
|
||||||
std::map<StringID, StringEntry> string_entries_;
|
std::map<StringID, StringEntry> string_entries_;
|
||||||
std::map<BoolID, BoolEntry> bool_entries_;
|
std::map<BoolID, BoolEntry> bool_entries_;
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
namespace ballistica {
|
namespace ballistica {
|
||||||
|
|
||||||
// These are set automatically via script; don't change here.
|
// These are set automatically via script; don't change here.
|
||||||
const int kAppBuildNumber = 20249;
|
const int kAppBuildNumber = 20256;
|
||||||
const char* kAppVersion = "1.5.29";
|
const char* kAppVersion = "1.5.29";
|
||||||
|
|
||||||
// Our standalone globals.
|
// Our standalone globals.
|
||||||
|
|||||||
@ -507,6 +507,27 @@ void Game::UpdateKickVote() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::HandleQuitOnIdle() {
|
||||||
|
if (idle_exit_minutes_) {
|
||||||
|
float idle_seconds{g_input->input_idle_time() * 0.001f};
|
||||||
|
if (!idle_exiting_ && idle_seconds > (idle_exit_minutes_.value() * 60.0f)) {
|
||||||
|
idle_exiting_ = true;
|
||||||
|
|
||||||
|
PushCall([this, idle_seconds] {
|
||||||
|
assert(InGameThread());
|
||||||
|
|
||||||
|
// Special exit value the wrapper script looks for to know we
|
||||||
|
// idled out.
|
||||||
|
g_app_globals->return_value = 154;
|
||||||
|
|
||||||
|
// Just go through _ba.quit()
|
||||||
|
// FIXME: Shouldn't need to go out to the python layer here...
|
||||||
|
g_python->obj(Python::ObjID::kQuitCall).Call();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bring our scenes, real-time timers, etc up to date.
|
// Bring our scenes, real-time timers, etc up to date.
|
||||||
void Game::Update() {
|
void Game::Update() {
|
||||||
assert(InGameThread());
|
assert(InGameThread());
|
||||||
@ -521,6 +542,8 @@ void Game::Update() {
|
|||||||
g_input->Update();
|
g_input->Update();
|
||||||
UpdateKickVote();
|
UpdateKickVote();
|
||||||
|
|
||||||
|
HandleQuitOnIdle();
|
||||||
|
|
||||||
// Send the game roster to our clients if it's changed recently.
|
// Send the game roster to our clients if it's changed recently.
|
||||||
if (game_roster_dirty_) {
|
if (game_roster_dirty_) {
|
||||||
if (real_time > last_game_roster_send_time_ + 2500) {
|
if (real_time > last_game_roster_send_time_ + 2500) {
|
||||||
@ -548,9 +571,9 @@ void Game::Update() {
|
|||||||
|
|
||||||
// TODO(ericf): On modern systems (VR and otherwise) we'll see 80hz, 90hz,
|
// TODO(ericf): On modern systems (VR and otherwise) we'll see 80hz, 90hz,
|
||||||
// 120hz, 240hz, etc. It would be great to generalize this to gravitate
|
// 120hz, 240hz, etc. It would be great to generalize this to gravitate
|
||||||
// towards clean step patterns in all cases, not just the 60hz and 90hz cases
|
// towards clean step patterns in all cases, not just the 60hz and 90hz
|
||||||
// we handle now. In general we want stuff like 1,1,2,1,1,2,1,1,2, not
|
// cases we handle now. In general we want stuff like 1,1,2,1,1,2,1,1,2,
|
||||||
// 1,1,1,2,1,2,2,1,1.
|
// not 1,1,1,2,1,2,2,1,1.
|
||||||
|
|
||||||
// Figure out where our net-time *should* be getting to to match real-time.
|
// Figure out where our net-time *should* be getting to to match real-time.
|
||||||
millisecs_t target_master_time = real_time + master_time_offset_;
|
millisecs_t target_master_time = real_time + master_time_offset_;
|
||||||
@ -1212,7 +1235,7 @@ void Game::Draw() {
|
|||||||
g_graphics->BuildAndPushFrameDef();
|
g_graphics->BuildAndPushFrameDef();
|
||||||
|
|
||||||
// Now bring the game up to date.
|
// Now bring the game up to date.
|
||||||
// By doing this *after* shipping a new frame_def we're reducing the
|
// By doing this *after* shipping a new frame-def we're reducing the
|
||||||
// chance of frame drops at the expense of adding a bit of visual latency.
|
// chance of frame drops at the expense of adding a bit of visual latency.
|
||||||
// Could maybe try to be smart about which to do first, but not sure
|
// Could maybe try to be smart about which to do first, but not sure
|
||||||
// if its worth it.
|
// if its worth it.
|
||||||
@ -1403,6 +1426,9 @@ void Game::ApplyConfig() {
|
|||||||
g_app_config->Resolve(AppConfig::BoolID::kDisableCameraGyro);
|
g_app_config->Resolve(AppConfig::BoolID::kDisableCameraGyro);
|
||||||
g_graphics->set_camera_gyro_explicitly_disabled(disable_camera_gyro);
|
g_graphics->set_camera_gyro_explicitly_disabled(disable_camera_gyro);
|
||||||
|
|
||||||
|
idle_exit_minutes_ =
|
||||||
|
g_app_config->Resolve(AppConfig::OptionalFloatID::kIdleExitMinutes);
|
||||||
|
|
||||||
// Any platform-specific settings.
|
// Any platform-specific settings.
|
||||||
g_platform->ApplyConfig();
|
g_platform->ApplyConfig();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -251,6 +252,7 @@ class Game : public Module {
|
|||||||
auto mark_game_roster_dirty() -> void { game_roster_dirty_ = true; }
|
auto mark_game_roster_dirty() -> void { game_roster_dirty_ = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
auto HandleQuitOnIdle() -> void;
|
||||||
auto InitSpecialChars() -> void;
|
auto InitSpecialChars() -> void;
|
||||||
auto Draw() -> void;
|
auto Draw() -> void;
|
||||||
auto PartyInvite(const std::string& name, const std::string& invite_id)
|
auto PartyInvite(const std::string& name, const std::string& invite_id)
|
||||||
@ -265,13 +267,6 @@ class Game : public Module {
|
|||||||
auto ScoresToBeatResponse(bool success, const std::list<ScoreToBeat>& scores,
|
auto ScoresToBeatResponse(bool success, const std::list<ScoreToBeat>& scores,
|
||||||
void* py_callback) -> void;
|
void* py_callback) -> void;
|
||||||
|
|
||||||
#if BA_VR_BUILD
|
|
||||||
VRHandsState vr_hands_state_;
|
|
||||||
#endif
|
|
||||||
#if BA_RIFT_BUILD
|
|
||||||
int rift_step_index_{};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto Prune() -> void; // Periodic pruning of dead stuff.
|
auto Prune() -> void; // Periodic pruning of dead stuff.
|
||||||
auto Update() -> void;
|
auto Update() -> void;
|
||||||
auto Process() -> void;
|
auto Process() -> void;
|
||||||
@ -284,6 +279,13 @@ class Game : public Module {
|
|||||||
auto GetGameRosterMessage() -> std::vector<uint8_t>;
|
auto GetGameRosterMessage() -> std::vector<uint8_t>;
|
||||||
auto Shutdown(bool soft) -> void;
|
auto Shutdown(bool soft) -> void;
|
||||||
|
|
||||||
|
#if BA_VR_BUILD
|
||||||
|
VRHandsState vr_hands_state_;
|
||||||
|
#endif
|
||||||
|
#if BA_RIFT_BUILD
|
||||||
|
int rift_step_index_{};
|
||||||
|
#endif
|
||||||
|
|
||||||
std::unique_ptr<ConnectionSet> connections_;
|
std::unique_ptr<ConnectionSet> connections_;
|
||||||
std::list<std::pair<millisecs_t, PlayerSpec> > banned_players_;
|
std::list<std::pair<millisecs_t, PlayerSpec> > banned_players_;
|
||||||
std::list<std::string> chat_messages_;
|
std::list<std::string> chat_messages_;
|
||||||
@ -314,6 +316,8 @@ class Game : public Module {
|
|||||||
std::unordered_map<SpecialChar, std::string> special_char_strings_;
|
std::unordered_map<SpecialChar, std::string> special_char_strings_;
|
||||||
bool ran_app_launch_commands_{};
|
bool ran_app_launch_commands_{};
|
||||||
bool kick_idle_players_{};
|
bool kick_idle_players_{};
|
||||||
|
std::optional<float> idle_exit_minutes_{};
|
||||||
|
bool idle_exiting_{};
|
||||||
std::unique_ptr<TimerList> realtimers_;
|
std::unique_ptr<TimerList> realtimers_;
|
||||||
Timer* process_timer_{};
|
Timer* process_timer_{};
|
||||||
Timer* headless_update_timer_{};
|
Timer* headless_update_timer_{};
|
||||||
|
|||||||
@ -268,7 +268,10 @@ void InputDevice::Update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InputDevice::UpdateLastInputTime() {
|
void InputDevice::UpdateLastInputTime() {
|
||||||
|
// Keep our own individual time, and also let
|
||||||
|
// the overall input system know something happened.
|
||||||
last_input_time_ = g_game->master_time();
|
last_input_time_ = g_game->master_time();
|
||||||
|
g_input->mark_input_active();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDevice::InputCommand(InputType type, float value) {
|
void InputDevice::InputCommand(InputType type, float value) {
|
||||||
|
|||||||
@ -22,18 +22,18 @@ class InputDevice : public Object {
|
|||||||
~InputDevice() override;
|
~InputDevice() override;
|
||||||
|
|
||||||
/// Called when the device is attached/detached to a local player.
|
/// Called when the device is attached/detached to a local player.
|
||||||
virtual void AttachToLocalPlayer(Player* player);
|
virtual auto AttachToLocalPlayer(Player* player) -> void;
|
||||||
virtual void AttachToRemotePlayer(ConnectionToHost* connection_to_host,
|
virtual auto AttachToRemotePlayer(ConnectionToHost* connection_to_host,
|
||||||
int remote_player_id);
|
int remote_player_id) -> void;
|
||||||
virtual void DetachFromPlayer();
|
virtual auto DetachFromPlayer() -> void;
|
||||||
|
|
||||||
/// Issues a command to the remote game to remove the player we're attached
|
/// Issues a command to the remote game to remove the player we're attached
|
||||||
/// to.
|
/// to.
|
||||||
void RemoveRemotePlayerFromGame();
|
auto RemoveRemotePlayerFromGame() -> void;
|
||||||
|
|
||||||
/// Return the (not necessarily unique) name of the input device.
|
/// Return the (not necessarily unique) name of the input device.
|
||||||
auto GetDeviceName() -> std::string;
|
auto GetDeviceName() -> std::string;
|
||||||
virtual void ResetHeldStates();
|
virtual auto ResetHeldStates() -> void;
|
||||||
|
|
||||||
/// Return the default base player name for players using this input device.
|
/// Return the default base player name for players using this input device.
|
||||||
virtual auto GetDefaultPlayerName() -> std::string;
|
virtual auto GetDefaultPlayerName() -> std::string;
|
||||||
@ -69,10 +69,10 @@ class InputDevice : public Object {
|
|||||||
auto index() const -> int { return index_; }
|
auto index() const -> int { return index_; }
|
||||||
|
|
||||||
/// Read new control values from config.
|
/// Read new control values from config.
|
||||||
virtual void UpdateMapping() {}
|
virtual auto UpdateMapping() -> void {}
|
||||||
|
|
||||||
/// Called during the game loop - for manual button repeats, etc.
|
/// Called during the game loop - for manual button repeats, etc.
|
||||||
virtual void Update();
|
virtual auto Update() -> void;
|
||||||
|
|
||||||
/// Return client id or -1 if local.
|
/// Return client id or -1 if local.
|
||||||
virtual auto GetClientID() const -> int;
|
virtual auto GetClientID() const -> int;
|
||||||
@ -81,7 +81,7 @@ class InputDevice : public Object {
|
|||||||
virtual auto IsRemoteClient() const -> bool;
|
virtual auto IsRemoteClient() const -> bool;
|
||||||
|
|
||||||
#if BA_SDL_BUILD || BA_MINSDL_BUILD
|
#if BA_SDL_BUILD || BA_MINSDL_BUILD
|
||||||
virtual void HandleSDLEvent(const SDL_Event* e) {}
|
virtual auto HandleSDLEvent(const SDL_Event* e) -> void {}
|
||||||
#endif
|
#endif
|
||||||
virtual auto GetAllowsConfiguring() -> bool { return true; }
|
virtual auto GetAllowsConfiguring() -> bool { return true; }
|
||||||
|
|
||||||
@ -121,26 +121,14 @@ class InputDevice : public Object {
|
|||||||
auto has_py_ref() -> bool { return (py_ref_ != nullptr); }
|
auto has_py_ref() -> bool { return (py_ref_ != nullptr); }
|
||||||
auto last_input_time() const -> millisecs_t { return last_input_time_; }
|
auto last_input_time() const -> millisecs_t { return last_input_time_; }
|
||||||
virtual auto ShouldBeHiddenFromUser() -> bool;
|
virtual auto ShouldBeHiddenFromUser() -> bool;
|
||||||
static void ResetRandomNames();
|
static auto ResetRandomNames() -> void;
|
||||||
|
|
||||||
protected:
|
|
||||||
void ShipBufferIfFull();
|
|
||||||
|
|
||||||
/// Pass some input command on to whatever we're connected to
|
|
||||||
/// (player or remote-player).
|
|
||||||
void InputCommand(InputType type, float value = 0.0f);
|
|
||||||
|
|
||||||
/// Called for all devices when they've successfully been added
|
|
||||||
/// to the input-device list, have a valid ID, name, etc.
|
|
||||||
virtual void ConnectionComplete() {}
|
|
||||||
|
|
||||||
/// Subclasses should call this to request a player in the local game.
|
|
||||||
void RequestPlayer();
|
|
||||||
|
|
||||||
/// Return a human-readable name for the device's type.
|
/// Return a human-readable name for the device's type.
|
||||||
/// This is used for display and also for storing configs/etc.
|
/// This is used for display and also for storing configs/etc.
|
||||||
virtual auto GetRawDeviceName() -> std::string { return "Input Device"; }
|
virtual auto GetRawDeviceName() -> std::string { return "Input Device"; }
|
||||||
|
|
||||||
|
auto number() const { return number_; }
|
||||||
|
|
||||||
/// Return any extra description for the device.
|
/// Return any extra description for the device.
|
||||||
/// This portion is only used for display and not for storing configs.
|
/// This portion is only used for display and not for storing configs.
|
||||||
/// An example is Mac PS3 controllers; they return "(bluetooth)" or "(usb)"
|
/// An example is Mac PS3 controllers; they return "(bluetooth)" or "(usb)"
|
||||||
@ -152,28 +140,45 @@ class InputDevice : public Object {
|
|||||||
/// a string.
|
/// a string.
|
||||||
virtual auto GetDeviceIdentifier() -> std::string { return ""; }
|
virtual auto GetDeviceIdentifier() -> std::string { return ""; }
|
||||||
|
|
||||||
|
/// Called for all devices when they've successfully been added
|
||||||
|
/// to the input-device list, have a valid ID, name, etc.
|
||||||
|
virtual auto ConnectionComplete() -> void {}
|
||||||
|
|
||||||
|
auto UpdateLastInputTime() -> void;
|
||||||
|
|
||||||
|
auto set_index(int index_in) -> void { index_ = index_in; }
|
||||||
|
auto set_numbered_identifier(int n) -> void { number_ = n; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
auto ShipBufferIfFull() -> void;
|
||||||
|
|
||||||
|
/// Pass some input command on to whatever we're connected to
|
||||||
|
/// (player or remote-player).
|
||||||
|
auto InputCommand(InputType type, float value = 0.0f) -> void;
|
||||||
|
|
||||||
|
/// Subclasses should call this to request a player in the local game.
|
||||||
|
auto RequestPlayer() -> void;
|
||||||
|
|
||||||
auto remote_player_id() const -> int { return remote_player_id_; }
|
auto remote_player_id() const -> int { return remote_player_id_; }
|
||||||
void UpdateLastInputTime();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
millisecs_t last_remote_input_commands_send_time_ = 0;
|
auto GetPyInputDevice(bool new_ref) -> PyObject*;
|
||||||
|
|
||||||
|
millisecs_t last_remote_input_commands_send_time_{};
|
||||||
std::vector<uint8_t> remote_input_commands_buffer_;
|
std::vector<uint8_t> remote_input_commands_buffer_;
|
||||||
|
|
||||||
// note: this is in base-net-time
|
// note: this is in base-net-time
|
||||||
millisecs_t last_input_time_ = 0;
|
millisecs_t last_input_time_{};
|
||||||
|
|
||||||
// We're attached to *one* of these two.
|
// We're attached to *one* of these two.
|
||||||
Object::WeakRef<Player> player_;
|
Object::WeakRef<Player> player_;
|
||||||
Object::WeakRef<ConnectionToHost> remote_player_;
|
Object::WeakRef<ConnectionToHost> remote_player_;
|
||||||
|
|
||||||
int remote_player_id_ = -1;
|
int remote_player_id_{-1};
|
||||||
PyObject* py_ref_ = nullptr;
|
PyObject* py_ref_{};
|
||||||
auto GetPyInputDevice(bool new_ref) -> PyObject*;
|
int index_{-1}; // Our overall device index.
|
||||||
void set_index(int index_in) { index_ = index_in; }
|
int number_{-1}; // Our type-specific number.
|
||||||
void set_numbered_identifier(int n) { number_ = n; }
|
|
||||||
int index_ = -1; // Our overall device index.
|
|
||||||
int number_ = -1; // Our type-specific number.
|
|
||||||
friend class Input;
|
|
||||||
BA_DISALLOW_CLASS_COPIES(InputDevice);
|
BA_DISALLOW_CLASS_COPIES(InputDevice);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -411,7 +411,7 @@ auto Input::GetNewNumberedIdentifier(const std::string& name,
|
|||||||
// suffix that's not taken.
|
// suffix that's not taken.
|
||||||
for (auto&& i : input_devices_) {
|
for (auto&& i : input_devices_) {
|
||||||
if (i.exists()) {
|
if (i.exists()) {
|
||||||
if ((i->GetRawDeviceName() == name) && i->number_ == num) {
|
if ((i->GetRawDeviceName() == name) && i->number() == num) {
|
||||||
in_use = true;
|
in_use = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -717,18 +717,18 @@ auto Input::GetLocalActiveInputDeviceCount() -> int {
|
|||||||
|
|
||||||
// This can get called alot so lets cache the value.
|
// This can get called alot so lets cache the value.
|
||||||
millisecs_t current_time = g_game->master_time();
|
millisecs_t current_time = g_game->master_time();
|
||||||
if (current_time != last_have_many_local_active_input_devices_check_time_) {
|
if (current_time != last_get_local_active_input_device_count_check_time_) {
|
||||||
last_have_many_local_active_input_devices_check_time_ = current_time;
|
last_get_local_active_input_device_count_check_time_ = current_time;
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (auto& input_device : input_devices_) {
|
for (auto& input_device : input_devices_) {
|
||||||
// Only count non-keyboard, non-touchscreen, local devices that have been
|
// Tally up local non-keyboard, non-touchscreen devices that have been
|
||||||
// used in the last minute.
|
// used in the last minute.
|
||||||
if (input_device.exists() && !(*input_device).IsKeyboard()
|
if (input_device.exists() && !input_device->IsKeyboard()
|
||||||
&& !(*input_device).IsTouchScreen() && !(*input_device).IsUIOnly()
|
&& !input_device->IsTouchScreen() && !input_device->IsUIOnly()
|
||||||
&& (*input_device).IsLocal()
|
&& input_device->IsLocal()
|
||||||
&& ((*input_device).last_input_time() != 0
|
&& (input_device->last_input_time() != 0
|
||||||
&& g_game->master_time() - (*input_device).last_input_time()
|
&& g_game->master_time() - input_device->last_input_time()
|
||||||
< 60000)) {
|
< 60000)) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -801,9 +801,9 @@ auto Input::ShouldCompletelyIgnoreInputDevice(InputDevice* input_device)
|
|||||||
return ignore_sdl_controllers_ && input_device->IsSDLController();
|
return ignore_sdl_controllers_ && input_device->IsSDLController();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Input::GetIdleTime() const -> millisecs_t {
|
// auto Input::GetIdleTime() const -> millisecs_t {
|
||||||
return GetRealTime() - last_input_time_;
|
// return GetRealTime() - last_input_time_;
|
||||||
}
|
// }
|
||||||
|
|
||||||
void Input::UpdateEnabledControllerSubsystems() {
|
void Input::UpdateEnabledControllerSubsystems() {
|
||||||
assert(IsBootstrapped());
|
assert(IsBootstrapped());
|
||||||
@ -872,6 +872,14 @@ void Input::Update() {
|
|||||||
if (real_time - last_input_device_count_update_time_ > incr) {
|
if (real_time - last_input_device_count_update_time_ > incr) {
|
||||||
UpdateInputDeviceCounts();
|
UpdateInputDeviceCounts();
|
||||||
last_input_device_count_update_time_ = real_time;
|
last_input_device_count_update_time_ = real_time;
|
||||||
|
|
||||||
|
// Keep our idle-time up to date.
|
||||||
|
if (input_active_) {
|
||||||
|
input_idle_time_ = 0;
|
||||||
|
} else {
|
||||||
|
input_idle_time_ += incr;
|
||||||
|
}
|
||||||
|
input_active_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& input_device : input_devices_) {
|
for (auto& input_device : input_devices_) {
|
||||||
@ -1080,7 +1088,7 @@ void Input::HandleBackPress(bool from_toolbar) {
|
|||||||
|
|
||||||
void Input::PushTextInputEvent(const std::string& text) {
|
void Input::PushTextInputEvent(const std::string& text) {
|
||||||
g_game->PushCall([this, text] {
|
g_game->PushCall([this, text] {
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
// Ignore if input is locked.
|
// Ignore if input is locked.
|
||||||
if (IsInputLocked()) {
|
if (IsInputLocked()) {
|
||||||
@ -1115,7 +1123,7 @@ void Input::HandleJoystickEvent(const SDL_Event& event,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make note that we're not idle.
|
// Make note that we're not idle.
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
// And that this particular device isn't idle either.
|
// And that this particular device isn't idle either.
|
||||||
input_device->UpdateLastInputTime();
|
input_device->UpdateLastInputTime();
|
||||||
@ -1139,7 +1147,7 @@ void Input::PushKeyReleaseEvent(const SDL_Keysym& keysym) {
|
|||||||
void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
||||||
assert(InGameThread());
|
assert(InGameThread());
|
||||||
|
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
// Ignore all key presses if input is locked.
|
// Ignore all key presses if input is locked.
|
||||||
if (IsInputLocked()) {
|
if (IsInputLocked()) {
|
||||||
@ -1304,7 +1312,7 @@ void Input::HandleKeyRelease(const SDL_Keysym* keysym) {
|
|||||||
|
|
||||||
// Note: we want to let these through even if input is locked.
|
// Note: we want to let these through even if input is locked.
|
||||||
|
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
// Give Python a crack at it for captures, etc.
|
// Give Python a crack at it for captures, etc.
|
||||||
if (g_python->HandleKeyReleaseEvent(*keysym)) {
|
if (g_python->HandleKeyReleaseEvent(*keysym)) {
|
||||||
@ -1381,7 +1389,7 @@ auto Input::HandleMouseScroll(const Vector2f& amount) -> void {
|
|||||||
if (IsInputLocked()) {
|
if (IsInputLocked()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
Widget* root_widget = g_ui->root_widget();
|
Widget* root_widget = g_ui->root_widget();
|
||||||
if (std::abs(amount.y) > 0.0001f && root_widget) {
|
if (std::abs(amount.y) > 0.0001f && root_widget) {
|
||||||
@ -1417,7 +1425,7 @@ auto Input::HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum)
|
|||||||
if (IsInputLocked()) {
|
if (IsInputLocked()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
Widget* root_widget = g_ui->root_widget();
|
Widget* root_widget = g_ui->root_widget();
|
||||||
@ -1447,7 +1455,7 @@ auto Input::PushMouseMotionEvent(const Vector2f& position) -> void {
|
|||||||
auto Input::HandleMouseMotion(const Vector2f& position) -> void {
|
auto Input::HandleMouseMotion(const Vector2f& position) -> void {
|
||||||
assert(g_graphics);
|
assert(g_graphics);
|
||||||
assert(InGameThread());
|
assert(InGameThread());
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
float old_cursor_pos_x = cursor_pos_x_;
|
float old_cursor_pos_x = cursor_pos_x_;
|
||||||
float old_cursor_pos_y = cursor_pos_y_;
|
float old_cursor_pos_y = cursor_pos_y_;
|
||||||
@ -1508,7 +1516,7 @@ auto Input::HandleMouseDown(int button, const Vector2f& position) -> void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
last_mouse_move_time_ = GetRealTime();
|
last_mouse_move_time_ = GetRealTime();
|
||||||
mouse_move_count_++;
|
mouse_move_count_++;
|
||||||
@ -1575,7 +1583,7 @@ auto Input::PushMouseUpEvent(int button, const Vector2f& position) -> void {
|
|||||||
|
|
||||||
auto Input::HandleMouseUp(int button, const Vector2f& position) -> void {
|
auto Input::HandleMouseUp(int button, const Vector2f& position) -> void {
|
||||||
assert(InGameThread());
|
assert(InGameThread());
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
// Convert normalized view coords to our virtual ones.
|
// Convert normalized view coords to our virtual ones.
|
||||||
cursor_pos_x_ = g_graphics->PixelToVirtualX(
|
cursor_pos_x_ = g_graphics->PixelToVirtualX(
|
||||||
@ -1629,7 +1637,7 @@ void Input::HandleTouchEvent(const TouchEvent& e) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetIdleTime();
|
mark_input_active();
|
||||||
|
|
||||||
// float x = e.x;
|
// float x = e.x;
|
||||||
// float y = e.y;
|
// float y = e.y;
|
||||||
|
|||||||
@ -81,10 +81,11 @@ class Input {
|
|||||||
|
|
||||||
// Get the total idle time for the system.
|
// Get the total idle time for the system.
|
||||||
// FIXME - should better coordinate this with InputDevice::getLastUsedTime().
|
// FIXME - should better coordinate this with InputDevice::getLastUsedTime().
|
||||||
auto GetIdleTime() const -> millisecs_t;
|
// auto GetIdleTime() const -> millisecs_t;
|
||||||
|
|
||||||
// Should be called whenever user-input of some form comes through.
|
// Should be called whenever user-input of some form comes through.
|
||||||
auto ResetIdleTime() -> void { last_input_time_ = GetRealTime(); }
|
// auto ResetIdleTime() -> void { last_input_time_ = GetRealTime(); }
|
||||||
|
auto mark_input_active() { input_active_ = true; }
|
||||||
|
|
||||||
// Should be called regularly to update button repeats, etc.
|
// Should be called regularly to update button repeats, etc.
|
||||||
auto Update() -> void;
|
auto Update() -> void;
|
||||||
@ -128,6 +129,9 @@ class Input {
|
|||||||
auto PushDestroyKeyboardInputDevices() -> void;
|
auto PushDestroyKeyboardInputDevices() -> void;
|
||||||
auto PushCreateKeyboardInputDevices() -> void;
|
auto PushCreateKeyboardInputDevices() -> void;
|
||||||
|
|
||||||
|
/// Roughly how long in milliseconds have all input devices been idle.
|
||||||
|
auto input_idle_time() const { return input_idle_time_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto UpdateInputDeviceCounts() -> void;
|
auto UpdateInputDeviceCounts() -> void;
|
||||||
auto GetNewNumberedIdentifier(const std::string& name,
|
auto GetNewNumberedIdentifier(const std::string& name,
|
||||||
@ -151,8 +155,11 @@ class Input {
|
|||||||
auto UpdateModKeyStates(const SDL_Keysym* keysym, bool press) -> void;
|
auto UpdateModKeyStates(const SDL_Keysym* keysym, bool press) -> void;
|
||||||
auto CreateKeyboardInputDevices() -> void;
|
auto CreateKeyboardInputDevices() -> void;
|
||||||
auto DestroyKeyboardInputDevices() -> void;
|
auto DestroyKeyboardInputDevices() -> void;
|
||||||
|
|
||||||
|
bool input_active_{};
|
||||||
|
millisecs_t input_idle_time_{};
|
||||||
int local_active_input_device_count_{};
|
int local_active_input_device_count_{};
|
||||||
millisecs_t last_have_many_local_active_input_devices_check_time_{};
|
millisecs_t last_get_local_active_input_device_count_check_time_{};
|
||||||
std::unordered_map<std::string, std::unordered_map<std::string, int> >
|
std::unordered_map<std::string, std::unordered_map<std::string, int> >
|
||||||
reserved_identifiers_;
|
reserved_identifiers_;
|
||||||
int max_controller_count_so_far_{};
|
int max_controller_count_so_far_{};
|
||||||
@ -165,7 +172,7 @@ class Input {
|
|||||||
bool have_non_touch_inputs_{};
|
bool have_non_touch_inputs_{};
|
||||||
float cursor_pos_x_{};
|
float cursor_pos_x_{};
|
||||||
float cursor_pos_y_{};
|
float cursor_pos_y_{};
|
||||||
millisecs_t last_input_time_{};
|
// millisecs_t last_input_time_{};
|
||||||
millisecs_t last_click_time_{};
|
millisecs_t last_click_time_{};
|
||||||
millisecs_t double_click_time_{200};
|
millisecs_t double_click_time_{200};
|
||||||
millisecs_t last_mouse_move_time_{};
|
millisecs_t last_mouse_move_time_{};
|
||||||
|
|||||||
@ -177,7 +177,7 @@ auto PyGetIdleTime(PyObject* self, PyObject* args) -> PyObject* {
|
|||||||
BA_PYTHON_TRY;
|
BA_PYTHON_TRY;
|
||||||
Platform::SetLastPyCall("get_idle_time");
|
Platform::SetLastPyCall("get_idle_time");
|
||||||
return PyLong_FromLong(static_cast_check_fit<long>( // NOLINT
|
return PyLong_FromLong(static_cast_check_fit<long>( // NOLINT
|
||||||
g_input ? g_input->GetIdleTime() : 0));
|
g_input ? g_input->input_idle_time() : 0));
|
||||||
BA_PYTHON_CATCH;
|
BA_PYTHON_CATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,7 +964,7 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
|
|||||||
"\n"
|
"\n"
|
||||||
"(internal)\n"
|
"(internal)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Returns the amount of time since any game input has been processed"},
|
"Returns the amount of time since any game input has been received."},
|
||||||
|
|
||||||
{"set_have_mods", PySetHaveMods, METH_VARARGS,
|
{"set_have_mods", PySetHaveMods, METH_VARARGS,
|
||||||
"set_have_mods(have_mods: bool) -> None\n"
|
"set_have_mods(have_mods: bool) -> None\n"
|
||||||
|
|||||||
@ -2442,6 +2442,26 @@ auto Python::GetRawConfigValue(const char* name, float default_value) -> float {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Python::GetRawConfigValue(const char* name,
|
||||||
|
std::optional<float> default_value)
|
||||||
|
-> std::optional<float> {
|
||||||
|
assert(InGameThread());
|
||||||
|
assert(objexists(ObjID::kConfig));
|
||||||
|
PyObject* value = PyDict_GetItemString(obj(ObjID::kConfig).get(), name);
|
||||||
|
if (value == nullptr) {
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (value == Py_None) {
|
||||||
|
return std::optional<float>();
|
||||||
|
}
|
||||||
|
return GetPyFloat(value);
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
Log("expected a float for config value '" + std::string(name) + "'");
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto Python::GetRawConfigValue(const char* name, int default_value) -> int {
|
auto Python::GetRawConfigValue(const char* name, int default_value) -> int {
|
||||||
assert(InGameThread());
|
assert(InGameThread());
|
||||||
assert(objexists(ObjID::kConfig));
|
assert(objexists(ObjID::kConfig));
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -160,6 +161,8 @@ class Python {
|
|||||||
auto GetRawConfigValue(const char* name, const char* default_value)
|
auto GetRawConfigValue(const char* name, const char* default_value)
|
||||||
-> std::string;
|
-> std::string;
|
||||||
auto GetRawConfigValue(const char* name, float default_value) -> float;
|
auto GetRawConfigValue(const char* name, float default_value) -> float;
|
||||||
|
auto GetRawConfigValue(const char* name, std::optional<float> default_value)
|
||||||
|
-> std::optional<float>;
|
||||||
auto GetRawConfigValue(const char* name, int default_value) -> int;
|
auto GetRawConfigValue(const char* name, int default_value) -> int;
|
||||||
auto GetRawConfigValue(const char* name, bool default_value) -> bool;
|
auto GetRawConfigValue(const char* name, bool default_value) -> bool;
|
||||||
void SetRawConfigValue(const char* name, float value);
|
void SetRawConfigValue(const char* name, float value);
|
||||||
|
|||||||
@ -230,7 +230,6 @@ void UI::AddWidget(Widget* w, ContainerWidget* parent) {
|
|||||||
|
|
||||||
auto UI::SendWidgetMessage(const WidgetMessage& m) -> int {
|
auto UI::SendWidgetMessage(const WidgetMessage& m) -> int {
|
||||||
if (!root_widget_.exists()) {
|
if (!root_widget_.exists()) {
|
||||||
// Log("SendWidgetMessage() called before root widget created");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return root_widget_->HandleMessage(m);
|
return root_widget_->HandleMessage(m);
|
||||||
|
|||||||
@ -91,23 +91,26 @@ class ServerConfig:
|
|||||||
# http://bombsquadgame.com/accountquery?id=ACCOUNT_ID_HERE
|
# http://bombsquadgame.com/accountquery?id=ACCOUNT_ID_HERE
|
||||||
stats_url: Optional[str] = None
|
stats_url: Optional[str] = None
|
||||||
|
|
||||||
# If present, the server will attempt to gracefully exit after this
|
# If present, the server manager will attempt to gracefully exit after
|
||||||
# amount of time. A graceful exit can occur at the end of a series
|
# this amount of time. A graceful exit can occur at the end of a series
|
||||||
# or other opportune time.
|
# or other opportune time.
|
||||||
# Servers with no exit times set will run indefinitely (though the server
|
# Servers with no exit times set will run indefinitely, though the
|
||||||
# binary will be restarted periodically to clear any leaked memory).
|
# server binary will be restarted periodically to clear any memory
|
||||||
|
# leaks or other bad state.
|
||||||
clean_exit_minutes: Optional[float] = None
|
clean_exit_minutes: Optional[float] = None
|
||||||
|
|
||||||
# If present, the server will shut down immediately after the given
|
# If present, the server manager will shut down immediately after this
|
||||||
# amount of time). This can be useful as a fallback for clean_exit_time.
|
# amount of time. This can be useful as a fallback for clean_exit_time.
|
||||||
# Servers with no exit times set will run indefinitely (though the server
|
# Servers with no exit times set will run indefinitely, though the
|
||||||
# binary will be restarted periodically to clear any leaked memory).
|
# server binary will be restarted periodically to clear any memory
|
||||||
|
# leaks or other bad state.
|
||||||
unclean_exit_minutes: Optional[float] = None
|
unclean_exit_minutes: Optional[float] = None
|
||||||
|
|
||||||
# If present, the server will shut down immediately if this amount of
|
# If present, the server will shut down immediately if this amount of
|
||||||
# time passes with no connected clients.
|
# time passes with no activity from any players.
|
||||||
# Servers with no exit times set will run indefinitely (though the server
|
# Servers with no exit times set will run indefinitely, though the
|
||||||
# binary will be restarted periodically to clear any leaked memory).
|
# server binary will be restarted periodically to clear any memory
|
||||||
|
# leaks or other bad state.
|
||||||
idle_exit_minutes: Optional[float] = None
|
idle_exit_minutes: Optional[float] = None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -642,11 +642,11 @@ def _get_server_config_template_yaml(projroot: str) -> str:
|
|||||||
if vname == 'playlist_code':
|
if vname == 'playlist_code':
|
||||||
# User wouldn't want to pass the default of None here.
|
# User wouldn't want to pass the default of None here.
|
||||||
vval = 12345
|
vval = 12345
|
||||||
elif vname == 'clean_exit_time':
|
elif vname == 'clean_exit_minutes':
|
||||||
vval = 60
|
vval = 60
|
||||||
elif vname == 'unclean_exit_time':
|
elif vname == 'unclean_exit_minutes':
|
||||||
vval = 90
|
vval = 90
|
||||||
elif vname == 'idle_exit_time':
|
elif vname == 'idle_exit_minutes':
|
||||||
vval = 20
|
vval = 20
|
||||||
elif vname == 'stats_url':
|
elif vname == 'stats_url':
|
||||||
vval = ('https://mystatssite.com/'
|
vval = ('https://mystatssite.com/'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user