2019-01-24 16:43:03 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2018-04-13 17:19:50 +08:00
using System ;
using System.IO ;
2022-03-02 16:54:33 +08:00
using System.Runtime.Versioning ;
2021-11-28 17:00:06 +08:00
using osu.Desktop.LegacyIpc ;
2018-04-13 17:19:50 +08:00
using osu.Framework ;
2018-08-17 12:28:35 +08:00
using osu.Framework.Development ;
2018-08-03 18:25:55 +08:00
using osu.Framework.Logging ;
2018-04-13 17:19:50 +08:00
using osu.Framework.Platform ;
2022-06-21 03:21:16 +08:00
using osu.Game ;
2018-04-13 17:19:50 +08:00
using osu.Game.IPC ;
2018-11-06 13:49:09 +08:00
using osu.Game.Tournament ;
2022-07-12 14:42:20 +08:00
using SDL2 ;
2022-03-02 16:54:33 +08:00
using Squirrel ;
2018-07-10 19:30:08 +08:00
2018-04-13 17:19:50 +08:00
namespace osu.Desktop
{
public static class Program
{
2021-07-21 14:02:15 +08:00
private const string base_game_name = @"osu" ;
2021-11-28 21:24:42 +08:00
private static LegacyTcpIpcProvider legacyIpc ;
2018-04-13 17:19:50 +08:00
[STAThread]
2021-11-28 13:03:21 +08:00
public static void Main ( string [ ] args )
2018-04-13 17:19:50 +08:00
{
2022-03-02 16:54:33 +08:00
// run Squirrel first, as the app may exit after these run
if ( OperatingSystem . IsWindows ( ) )
2022-07-12 14:42:20 +08:00
{
var windowsVersion = Environment . OSVersion . Version ;
2022-07-12 15:16:46 +08:00
// While .NET 6 still supports Windows 7 and above, we are limited by realm currently, as they choose to only support 8.1 and higher.
// See https://www.mongodb.com/docs/realm/sdk/dotnet/#supported-platforms
if ( windowsVersion . Major < 6 | | ( windowsVersion . Major = = 6 & & windowsVersion . Minor < = 2 ) )
2022-07-12 14:42:20 +08:00
{
SDL . SDL_ShowSimpleMessageBox ( SDL . SDL_MessageBoxFlags . SDL_MESSAGEBOX_ERROR ,
"Your operating system is too old to run osu!" ,
2022-07-12 23:29:17 +08:00
"This version of osu! requires at least Windows 8.1 to run.\nPlease upgrade your operating system or consider using an older version of osu!." , IntPtr . Zero ) ;
2022-07-12 14:42:20 +08:00
return ;
}
2022-03-02 16:54:33 +08:00
setupSquirrel ( ) ;
2022-07-12 14:42:20 +08:00
}
2022-03-02 16:54:33 +08:00
2018-04-13 17:19:50 +08:00
// Back up the cwd before DesktopGameHost changes it
2021-10-27 12:04:41 +08:00
string cwd = Environment . CurrentDirectory ;
2018-04-13 17:19:50 +08:00
2021-07-21 14:02:15 +08:00
string gameName = base_game_name ;
2021-07-21 12:53:24 +08:00
bool tournamentClient = false ;
2021-07-21 08:12:44 +08:00
2021-10-27 12:04:41 +08:00
foreach ( string arg in args )
2021-07-21 08:12:44 +08:00
{
2021-10-27 12:04:41 +08:00
string [ ] split = arg . Split ( '=' ) ;
2021-07-21 14:02:15 +08:00
2021-10-27 12:04:41 +08:00
string key = split [ 0 ] ;
string val = split . Length > 1 ? split [ 1 ] : string . Empty ;
2021-07-21 14:02:15 +08:00
switch ( key )
2021-07-21 12:53:24 +08:00
{
case "--tournament" :
tournamentClient = true ;
break ;
case "--debug-client-id" :
if ( ! DebugUtils . IsDebugBuild )
2021-07-21 14:02:15 +08:00
throw new InvalidOperationException ( "Cannot use this argument in a non-debug build." ) ;
if ( ! int . TryParse ( val , out int clientID ) )
throw new ArgumentException ( "Provided client ID must be an integer." ) ;
2021-07-21 12:53:24 +08:00
2021-07-21 14:02:15 +08:00
gameName = $"{base_game_name}-{clientID}" ;
2021-07-21 12:53:24 +08:00
break ;
}
2021-07-21 08:12:44 +08:00
}
2022-01-25 13:16:15 +08:00
using ( DesktopGameHost host = Host . GetSuitableDesktopHost ( gameName , new HostOptions { BindIPC = true } ) )
2018-04-13 17:19:50 +08:00
{
if ( ! host . IsPrimaryInstance )
{
2022-06-21 03:21:16 +08:00
if ( trySendIPCMessage ( host , cwd , args ) )
2021-11-28 13:03:21 +08:00
return ;
2019-07-23 12:38:05 +08:00
// we want to allow multiple instances to be started when in debug.
if ( ! DebugUtils . IsDebugBuild )
2021-09-21 17:00:54 +08:00
{
Logger . Log ( @"osu! does not support multiple running instances." , LoggingTarget . Runtime , LogLevel . Error ) ;
2021-11-28 13:03:21 +08:00
return ;
2021-09-21 17:00:54 +08:00
}
2018-04-13 17:19:50 +08:00
}
2019-07-23 12:38:05 +08:00
2021-11-28 20:15:29 +08:00
if ( host . IsPrimaryInstance )
{
2021-11-28 21:24:42 +08:00
try
{
Logger . Log ( "Starting legacy IPC provider..." ) ;
legacyIpc = new LegacyTcpIpcProvider ( ) ;
legacyIpc . Bind ( ) ;
}
catch ( Exception ex )
{
Logger . Error ( ex , "Failed to start legacy IPC provider" ) ;
}
2021-11-28 20:15:29 +08:00
}
2021-07-21 12:53:24 +08:00
if ( tournamentClient )
2021-07-21 08:12:44 +08:00
host . Run ( new TournamentGame ( ) ) ;
else
host . Run ( new OsuGameDesktop ( args ) ) ;
2018-04-13 17:19:50 +08:00
}
}
2018-08-03 18:25:55 +08:00
2022-06-21 03:21:16 +08:00
private static bool trySendIPCMessage ( IIpcHost host , string cwd , string [ ] args )
{
if ( args . Length = = 1 & & args [ 0 ] . StartsWith ( OsuGameBase . OSU_PROTOCOL , StringComparison . Ordinal ) )
{
var osuSchemeLinkHandler = new OsuSchemeLinkIPCChannel ( host ) ;
if ( ! osuSchemeLinkHandler . HandleLinkAsync ( args [ 0 ] ) . Wait ( 3000 ) )
throw new IPCTimeoutException ( osuSchemeLinkHandler . GetType ( ) ) ;
return true ;
}
if ( args . Length > 0 & & args [ 0 ] . Contains ( '.' ) ) // easy way to check for a file import in args
{
var importer = new ArchiveImportIPCChannel ( host ) ;
foreach ( string file in args )
{
Console . WriteLine ( @"Importing {0}" , file ) ;
if ( ! importer . ImportAsync ( Path . GetFullPath ( file , cwd ) ) . Wait ( 3000 ) )
throw new IPCTimeoutException ( importer . GetType ( ) ) ;
}
return true ;
}
return false ;
}
2022-03-02 16:54:33 +08:00
[SupportedOSPlatform("windows")]
private static void setupSquirrel ( )
{
2022-06-24 20:25:23 +08:00
SquirrelAwareApp . HandleEvents ( onInitialInstall : ( _ , tools ) = >
2022-03-02 16:54:33 +08:00
{
tools . CreateShortcutForThisExe ( ) ;
2022-03-03 02:54:39 +08:00
tools . CreateUninstallerRegistryEntry ( ) ;
2022-06-24 20:25:23 +08:00
} , onAppUpdate : ( _ , tools ) = >
2022-04-26 13:48:12 +08:00
{
tools . CreateUninstallerRegistryEntry ( ) ;
2022-06-24 20:25:23 +08:00
} , onAppUninstall : ( _ , tools ) = >
2022-03-02 16:54:33 +08:00
{
tools . RemoveShortcutForThisExe ( ) ;
tools . RemoveUninstallerRegistryEntry ( ) ;
2022-06-24 20:25:23 +08:00
} , onEveryRun : ( _ , _ , _ ) = >
2022-03-02 16:54:33 +08:00
{
2022-04-25 17:37:35 +08:00
// While setting the `ProcessAppUserModelId` fixes duplicate icons/shortcuts on the taskbar, it currently
// causes the right-click context menu to function incorrectly.
//
// This may turn out to be non-required after an alternative solution is implemented.
// see https://github.com/clowd/Clowd.Squirrel/issues/24
// tools.SetProcessAppUserModelId();
2022-03-02 16:54:33 +08:00
} ) ;
}
2021-11-28 13:03:21 +08:00
}
2018-04-13 17:19:50 +08:00
}