diff --git a/.efrocachemap b/.efrocachemap index efdc030f..4b2d5e86 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3932,26 +3932,26 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/41/1773777bea8220fb532b02207bd8", - "build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/aa/7db23036581440bd28d245f7b6b0", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e2/ef/7254a413f4bb7618b9d7898d6a7f", - "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/64/71ddea075764913a51b13c331d88", - "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ee/bf/5aa9ef09d3adf56836c0370e587e", - "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/91/b6/f323561fb316ba15a3f5d7d45858", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bc/a6/88edc1066bc69f967a924e84fc5b", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/96/b6/2ba6d3b0ef4dff3a0a1e1fb7b5da", - "build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4b/af/8a1214609ee5f0d207905e384394", - "build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/2a/90/f7532756dd8a21f1a07c1ed12ccc", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/86/a0506a90f1a5845843affb842e09", - "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a3/2b/3127e1a79e6e3aece248ef41ec8c", - "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ae/31/3542167c07e9abd5f1df07d08181", - "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/94/5a/e3b3c60976be78d1728660c638b3", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7a/b2/ca6ad8142f08e81d63d65f52e0ce", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c9/62/4b17a374c663c730e091a1695911", - "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/75/11/0bbb84a7d2f285e97d5f6e8b8c5e", - "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d9/89/1d495c48545be16152915c5933ab", - "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/77/71/570b0118c6e2fe3603b9832a2991", - "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/29/dd/2646ab0b39c07c541ad80a7b4727", + "build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/84/a1/420d282610456205a0c7317ef587", + "build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a9/63/eabb9fe980c4686ff48c62dc3215", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/3f/7bc2491bcb678a964043ba7d25dd", + "build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ee/12/8addc0aa42af13c2e2903b1f2cb1", + "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/00/11/ca95947488543f6e9fcb6ff4a122", + "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/d9/e4f7c8454210a1bedef3416d1768", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/b9/21faa11f5b965f55e548b6485b2c", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/aa/b1641c07d4539f673445467ccef9", + "build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ac/a3/ff8cbd9b0bae767ad4809360e21a", + "build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/46/ee/4c5599f4b9aef54eff51b7702409", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/db/ce/aec9518eee7bcd7fdc8ca80b1d76", + "build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d8/dc/6b1c63cb28db2ff64554526d5311", + "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/fa/8613c74733350c3cd26945823ed0", + "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/10/65/62b7f0eb542a037f54ea486be204", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/89/6e/569b32f6c9401b17ceed5327257f", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/dc/5a55ebdf3e5541c74a59f68f3f65", + "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9c/58/1be66154a04eab5f00f6aa92d165", + "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bd/89/b6210c67baf254ab314317973b5e", + "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/93/41/617d1b3436173551780992842b6e", + "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3e/c5/d5a2841dc15918206f8c19b1ce02", "build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/bf/393694ea67f3d590dd2706c9955e", "build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/78/cb/bb9ae4f896f862074057c8e36e1d", "build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ae/bd/39d7b885f7f01e81d0e96f0f85ce", @@ -3960,12 +3960,12 @@ "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/52/d9/563a6949d2c4db5a915c54460fbc", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d0/6a/42fe8d2e34f95e1b3282e8422344", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/50/cf/bad44b07a4022aee3001002086b5", - "build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/84/d0/d46d2ce177f1ce6bc0304ce673c9", - "build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/09/b7/e094fdfa54fa38751f0caa1c9e68", - "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/69/6f/c99b2718ac104de79337e35414f7", - "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d7/76/eecf9cc91f73e3cae73291215216", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/77/0f/0ef7575b11fd70a1d897ab261813", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/45/62/8267446a6c71bcc34234ec5e119a", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/78/9b/a5a29e1baa7d5d9d2eaabc9412f9", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ab/67/4c447ca41efd957bce227a34887c" + "build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fa/8a/a6aedb3b2c74c055005792710be8", + "build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4b/97/0b6acf3397515a5fb997b3a81e3d", + "build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ee/b0/81fbb6e8996205a16e3d8e912000", + "build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/64/68/e668be0a349bcdd51efe35703b8a", + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4b/06/3e80d9b9efa82e28b77d895562b0", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/34/b1/942b8c6206051dbaa15f225bc8d9", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e1/a6/2b3a07d7afe0215ab5843a83809f", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/48/5d/e8c8deb5b42593c805fa9c181c0c" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ee6f52a4..ca594108 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ - Added ba.clipboard_* functions for copying and pasting text on supported platforms. - Implemented clipboard functionality on SDL based builds (such as prefab). - Fixed an issue where click locations on scaled text fields could be incorrectly calculated. +- Server-wrapper improvements allowing config path and ba_root path to be passed explicitly. +- Binary -cfgdir option now properly allows any path, not just './ba_root'. ### 1.5.29 (20246) - Exposed ba method/class initing in public C++ layer. diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index b8ad800a..12b2db4e 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -10,6 +10,7 @@ import signal import subprocess import sys import time +from dataclasses import dataclass from pathlib import Path from threading import Lock, Thread, current_thread from typing import TYPE_CHECKING @@ -36,7 +37,7 @@ VERSION_STR = '1.1.2' # Version history: # 1.1.2: -# Now accepts config path as sole optional argument. +# Added args for setting config path and ba_root path # 1.1.1: # Switched config reading to use efro.dataclasses.dataclass_from_dict() # 1.1.0: @@ -58,8 +59,10 @@ class ServerManagerApp: managing BallisticaCore operating in server mode. """ - def __init__(self, config_path: Optional[str] = None) -> None: - self._config_path = config_path + def __init__(self, args: Args) -> None: + self._config_path = args.config_path + self._ba_root_path = (args.ba_root_path if args.ba_root_path + is not None else os.path.abspath('dist/ba_root')) try: self._config = self._load_config() except Exception as exc: @@ -336,8 +339,9 @@ class ServerManagerApp: print(f'{Clr.CYN}Launching server subprocess...{Clr.RST}') binary_name = ('ballisticacore_headless.exe' if os.name == 'nt' else './ballisticacore_headless') + assert self._ba_root_path is not None self._subprocess = subprocess.Popen( - [binary_name, '-cfgdir', 'ba_root'], + [binary_name, '-cfgdir', self._ba_root_path], stdin=subprocess.PIPE, cwd='dist') @@ -363,9 +367,12 @@ class ServerManagerApp: def _prep_subprocess_environment(self) -> None: """Write files that must exist at process launch.""" - os.makedirs('dist/ba_root', exist_ok=True) - if os.path.exists('dist/ba_root/config.json'): - with open('dist/ba_root/config.json') as infile: + + assert self._ba_root_path is not None + os.makedirs(self._ba_root_path, exist_ok=True) + cfgpath = os.path.join(self._ba_root_path, 'config.json') + if os.path.exists(cfgpath): + with open(cfgpath) as infile: bincfg = json.loads(infile.read()) else: bincfg = {} @@ -376,7 +383,7 @@ class ServerManagerApp: bincfg['Auto Balance Teams'] = self._config.auto_balance_teams 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(cfgpath, 'w') as outfile: outfile.write(json.dumps(bincfg)) def _enqueue_server_command(self, command: ServerCommand) -> None: @@ -544,22 +551,61 @@ def _parse_args() -> Optional[str]: return None +@dataclass +class Args: + """Wraps arguments that can be passed from the command line.""" + config_path: Optional[str] = None + ba_root_path: Optional[str] = None + + @classmethod + def from_command_line(cls) -> Args: + """Parse command line args and fill ourself out.""" + args = Args() + + i = 1 + argc = len(sys.argv) + while i < argc: + arg = sys.argv[i] + if arg == '--config': + if i + 1 >= argc: + raise CleanError('Expected a config path as next arg.') + path = sys.argv[i + 1] + if not os.path.exists(path): + raise CleanError( + f"Supplied path does not exist: '{path}'.") + args.config_path = os.path.abspath(path) + i += 2 + elif arg == '--root': + if i + 1 >= argc: + raise CleanError('Expected a path as next arg.') + path = sys.argv[i + 1] + # Note: this one doesn't have to exist. + args.ba_root_path = os.path.abspath(path) + i += 2 + else: + raise CleanError(f"Invalid arg: '{arg}'.") + + return args + + def main() -> None: """Run a BallisticaCore server manager in interactive mode.""" try: - # User can optionally supply a config path. - # (need to get this before we chdir). - config_path = _parse_args() + # Note: we need to parse args before we chdir since we might be + # dealing with relative paths. + args = Args.from_command_line() # ServerManager expects cwd to be the server dir (containing - # dist/, config.yaml, etc.) - # Let's change our working directory to the location of this file - # so we can run this script from anywhere and it'll work. + # dist/, config.yaml, etc.) Let's change our working directory to + # the location of this file so we can run this script from anywhere + # and it'll work. os.chdir(os.path.abspath(os.path.dirname(__file__))) - ServerManagerApp(config_path=config_path).run_interactive() + ServerManagerApp(args).run_interactive() + except CleanError as exc: # For clean errors, do a simple print and fail; no tracebacks/etc. + # Any others will bubble up and give us the usual mess. exc.pretty_print() sys.exit(1) diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 5027608e..e2a541f5 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -21,7 +21,7 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20300; +const int kAppBuildNumber = 20303; const char* kAppVersion = "1.6.0"; // Our standalone globals. diff --git a/src/ballistica/platform/platform.cc b/src/ballistica/platform/platform.cc index 175d7efe..d90cdb0f 100644 --- a/src/ballistica/platform/platform.cc +++ b/src/ballistica/platform/platform.cc @@ -572,25 +572,22 @@ static void HandleArgs(int argc, char** argv) { if (i + 1 < argc) { g_app_globals->user_config_dir = argv[i + 1]; - // Need to remove this limitation!!! - // Don't remember why it's here; something about not being able to - // create nested directories properly in windows. But perhaps we - // can just error if a dir is provided that's invalid. - if (g_app_globals->user_config_dir != "ba_root") { - printf("%s", "ERROR: -cfgdir currently has to be 'ba_root'\n"); - fflush(stdout); - exit(-1); - } - // Need to convert this to an abs path since we chdir soon. - std::string buffer = g_platform->GetCWD(); - if (buffer.empty()) { - printf("%s", "ERROR: unable to get cwd for cfgdir setup\n"); + bool success = + g_platform->AbsPath(argv[i + 1], &g_app_globals->user_config_dir); + if (!success) { + // This can fail if the path doesn't exist. + if (!g_platform->FilePathExists(argv[i + 1])) { + printf("ERROR: provided config dir does not exist: '%s'\n", + argv[i + 1]); + } else { + printf( + "ERROR: unable to determine absolute path of config dir '%s'\n", + argv[i + 1]); + } fflush(stdout); exit(-1); } - g_app_globals->user_config_dir = - std::string(buffer) + BA_DIRSLASH + g_app_globals->user_config_dir; } else { Log("ERROR: expected arg after -cfgdir"); exit(-1); @@ -1150,6 +1147,30 @@ void Platform::Unlink(const char* path) { #endif } +auto Platform::AbsPath(const std::string& path, std::string* outpath) -> bool { + // Ensure all implementations fail if the file does not exist. + if (!FilePathExists(path)) { + return false; + } + return DoAbsPath(path, outpath); +} + +auto Platform::DoAbsPath(const std::string& path, std::string* outpath) + -> bool { + // This covers all but windows. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + char buffer[PATH_MAX + 1]; + char* ptr = realpath(path.c_str(), buffer); + if (ptr) { + *outpath = ptr; + return true; + } + return false; +#endif +} + auto Platform::IsEventPushMode() -> bool { return false; } auto Platform::GetDisplayResolution(int* x, int* y) -> bool { return false; } diff --git a/src/ballistica/platform/platform.h b/src/ballistica/platform/platform.h index 1eda05b4..cc897966 100644 --- a/src/ballistica/platform/platform.h +++ b/src/ballistica/platform/platform.h @@ -105,6 +105,10 @@ class Platform { // Unlink a file. virtual auto Unlink(const char* path) -> void; + /// Return the absolute path for the provided path. Note that this requires + /// the path to already exist. + auto AbsPath(const std::string& path, std::string* outpath) -> bool; + #pragma mark CLIPBOARD --------------------------------------------------------- /// Return whether clipboard operations are supported at all. @@ -494,6 +498,10 @@ class Platform { // Should not except if it already exists or if quiet is true. virtual void DoMakeDir(const std::string& dir, bool quiet); + // Attempt to actually get an abs path. This will only be called if + // the path is valid and exists. + virtual auto DoAbsPath(const std::string& path, std::string* outpath) -> bool; + // Calc the user scripts dir path for this platform. // This will be called once and the path cached. virtual auto DoGetUserPythonDirectory() -> std::string;