using Sandbox.Engine; namespace Sandbox; public static partial class MenuUtility { static CancellationTokenSource gameLoadingCts = new CancellationTokenSource(); /// /// Close the current game. /// public static void CloseGame() { // Editor only: just exit playmode if ( IToolsDll.Current is not null ) { IToolsDll.Current.ExitPlaymode(); return; } gameLoadingCts?.Cancel(); if ( IGameInstance.Current is not null ) { IGameInstance.Current?.Close(); } else { // Conna: game instance will call disconnect. If we don't have a game instance then we // need to call it ourselves. Networking.Disconnect(); Application.ClearGame(); } LaunchArguments.Reset(); } /// /// A game has been opened. Load the game. If allowLaunchOverride then special launch conditions will be obeyed. /// For example, we might join a lobby instead of loading the game, or we might open the launcher. /// public static void OpenGame( string ident, bool allowLaunchOverride = true, Dictionary gameSettings = null ) { gameLoadingCts?.Cancel(); gameLoadingCts = new CancellationTokenSource(); if ( gameSettings is not null ) LaunchArguments.GameSettings = gameSettings; _ = LoadAsync( ident, allowLaunchOverride, gameLoadingCts.Token ); } /// /// A game has been opened. Load the game. /// public static void OpenGameWithMap( string gameident, string mapName, Dictionary gameSettings = null ) { LaunchArguments.Map = mapName; if ( gameSettings is not null ) LaunchArguments.GameSettings = gameSettings; OpenGame( gameident, false ); } static async Task LoadAsync( string ident, bool allowLaunchOverride, CancellationToken ct ) { ThreadSafe.AssertIsMainThread(); LoadingScreen.IsVisible = true; LoadingScreen.Media = null; LoadingScreen.Title = "Loading Game.."; var package = await Package.FetchAsync( ident, false ); if ( package is not null ) { LoadingScreen.Title = package.Title; LoadingScreen.Media = package.LoadingScreen.MediaUrl; } var flags = GameLoadingFlags.Host | GameLoadingFlags.Reload; if ( Application.IsEditor ) flags |= GameLoadingFlags.Developer; // todo - is the package we're loading a local package await IGameInstanceDll.Current.LoadGamePackageAsync( ident, flags, ct ); } static bool _isJoiningLobby; /// /// Try to join any lobby for this game. /// public static async Task TryJoinLobby( string ident ) { if ( _isJoiningLobby ) return false; try { _isJoiningLobby = true; var lobbies = await Networking.QueryLobbies( ident ); var orderedLobbies = lobbies.OrderBy( lobby => lobby.ContainsFriends ) .ThenByDescending( lobby => lobby.Members ); foreach ( var lobby in orderedLobbies ) { if ( lobby.IsFull ) continue; // We might be in a game now if ( Game.InGame ) return false; Log.Info( $"Attempting to join available lobby {lobby.LobbyId}" ); // Try to join this one if ( await Networking.TryConnectSteamId( lobby.LobbyId ) ) return true; } Log.Info( $"Couldn't join a lobby - making a game" ); return false; } finally { _isJoiningLobby = false; } } }