├── .gitattributes ├── TranslationTools ├── .gitignore ├── .vscode │ ├── settings.json │ ├── tasks.json │ └── launch.json ├── compileAllMo.sh ├── TranslationTools.csproj ├── .editorconfig ├── TranslationDefinition.cs ├── applyTemplateChangesToAllPo.sh ├── EntryPoint.cs ├── updateTranslationPot.sh └── MiscTranslationFiles │ └── SteamStorePage │ ├── es.json │ ├── pt_BR.json │ ├── zh_Hans.json │ ├── sergal.json │ └── de.json ├── SS14.Launcher.FakeRobustToolbox ├── server │ ├── status │ ├── .gitignore │ ├── info │ └── run ├── README.md ├── SolutionFiles.tar.gz └── Robust.Client │ ├── Robust.Client.csproj │ └── Class1.cs ├── .vscode ├── settings.json ├── launch.json └── tasks.json ├── SolutionFiles.tar.gz ├── SS14.Launcher ├── Assets │ ├── icon.ico │ ├── logo-long.png │ ├── info-icons │ │ ├── web.png │ │ ├── wiki.png │ │ ├── discord.png │ │ ├── forum.png │ │ └── github.png │ └── Fonts │ │ └── noto_sans │ │ ├── NotoSans-Bold.ttf │ │ ├── NotoSans-Italic.ttf │ │ ├── NotoSans-Regular.ttf │ │ └── NotoSans-BoldItalic.ttf ├── Models │ ├── Data │ │ ├── Migrations │ │ │ ├── Script0004_RaiseTime.sql │ │ │ ├── Script0001_EngineModules.sql │ │ │ ├── Script0003_Indices.sql │ │ │ ├── Script0007_MVLoginMVKeyAuth.sql │ │ │ ├── Script0002_ContentDB.cs │ │ │ ├── Script0008_MVRemoveWizDenServers.sql │ │ │ ├── Script0005_Filters.sql │ │ │ ├── Script0006_Hubs.sql │ │ │ └── Script0000_Initial.sql │ │ ├── Hub.cs │ │ ├── InstalledEngineModule.cs │ │ ├── InstalledEngineVersion.cs │ │ ├── LoginInfoGuest.cs │ │ ├── LoginInfo.cs │ │ ├── LoginInfoAccount.cs │ │ ├── LoginInfoKey.cs │ │ ├── TypeHandlers.cs │ │ └── FavoriteServer.cs │ ├── OverrideAssets │ │ └── Migrations │ │ │ └── Script0001_Initial.sql │ ├── UpdateException.cs │ ├── ContentManagement │ │ ├── Migrations │ │ │ ├── Script0002_ContentIdIndex.sql │ │ │ └── Script0001_Blake2B.sql │ │ ├── Model.cs │ │ └── ContentCompressionScheme.cs │ ├── ContentLaunchInfo.cs │ ├── ServerStatus │ │ ├── IServerSource.cs │ │ ├── ServerStatusCode.cs │ │ └── IServerStatusData.cs │ ├── LoginToken.cs │ ├── Logins │ │ ├── AccountLoginStatus.cs │ │ └── LoggedInAccount.cs │ ├── LoginTokenExt.cs │ ├── ServerInfo.cs │ └── LauncherInfoManager.cs ├── AssemblyInfo.cs ├── Global.cs ├── signing_key ├── signing_key_multiverse ├── FodyWeavers.xml ├── ViewModels │ ├── Login │ │ ├── IErrorOverlayOwner.cs │ │ ├── BaseLoginViewModel.cs │ │ ├── AuthErrorsOverlayViewModel.cs │ │ ├── ExpiredLoginViewModel.cs │ │ ├── ResendConfirmationViewModel.cs │ │ ├── ForgotPasswordViewModel.cs │ │ └── AuthTfaViewModel.cs │ ├── IdentityTabs │ │ ├── IdentityTabViewModel.cs │ │ ├── AlreadyMadeTabViewModel.cs │ │ └── InformationTabViewModel.cs │ ├── MainWindowTabs │ │ ├── MainWindowTabViewModel.cs │ │ ├── NewsEntryViewModel.cs │ │ ├── DevelopmentTabViewModel.cs │ │ ├── ServerFilterViewModel.cs │ │ └── NewsTabViewModel.cs │ └── ViewModelBase.cs ├── Views │ ├── MainWindowAge.xaml.cs │ ├── MainWindowIdentity.xaml.cs │ ├── MainWindowTabs │ │ ├── ServerFilterView.xaml.cs │ │ ├── DevelopmentTabView.xaml.cs │ │ ├── NewsTabView.xaml.cs │ │ ├── ServerListFiltersView.xaml.cs │ │ ├── ServerFilterCounterView.xaml.cs │ │ ├── ServerListTabView.xaml.cs │ │ ├── ServerFilterView.xaml │ │ ├── ServerEntryView.xaml.cs │ │ ├── ServerFilterCounterView.xaml │ │ ├── OptionsTabView.xaml.cs │ │ ├── DevelopmentTabView.xaml │ │ ├── NewsTabView.xaml │ │ └── HomePageView.xaml.cs │ ├── IdentityTabs │ │ ├── LoginTabView.cs │ │ ├── AlreadyMadeTabView.cs │ │ ├── InformationTabView.cs │ │ ├── GuestTabView.cs │ │ ├── KeyNewTabView.cs │ │ ├── AlreadyMadeTabView.xaml │ │ ├── InformationTabView.xaml │ │ ├── KeyImportTabView.cs │ │ ├── KeyImportTabView.xaml │ │ ├── LoginTabView.xaml │ │ ├── GuestTabView.xaml │ │ └── KeyNewTabView.xaml │ ├── Login │ │ ├── ExpiredLoginView.xaml.cs │ │ ├── RegisterNeedsConfirmationView.xaml.cs │ │ ├── AuthTfaView.xaml.cs │ │ ├── ForgotPasswordView.xaml.cs │ │ ├── ResendConfirmationView.xaml.cs │ │ ├── RegisterView.xaml.cs │ │ ├── AuthErrorsOverlayView.xaml.cs │ │ ├── LoginView.xaml.cs │ │ ├── AuthErrorsOverlayView.xaml │ │ ├── RegisterNeedsConfirmationView.xaml │ │ ├── ForgotPasswordView.xaml │ │ ├── ResendConfirmationView.xaml │ │ ├── AuthTfaView.xaml │ │ ├── ExpiredLoginView.xaml │ │ └── RegisterView.xaml │ ├── MainWindowEighteenPlusInitialSetting.xaml.cs │ ├── RandomMessage.xaml.cs │ ├── DungSpinner.xaml │ ├── RandomMessage.xaml │ ├── ConnectingOverlay.xaml.cs │ ├── LanguageDropDown.xaml.cs │ ├── ServerInfoLinkControl.xaml │ ├── AccountDropDown.xaml.cs │ ├── IconLabel.cs │ ├── DirectConnectDialog.xaml │ ├── AddFavoriteDialog.xaml.cs │ ├── AddFavoriteDialog.xaml │ ├── ConfigureKeyDialog.xaml.cs │ ├── DirectConnectDialog.xaml.cs │ ├── ServerInfoLinkControl.xaml.cs │ ├── LanguageDropDown.xaml │ ├── AngleBox.cs │ ├── AccountDropDown.xaml │ ├── MainWindowIdentity.xaml │ └── HubSettingsDialog.xaml.cs ├── LauncherVersion.cs ├── Theme │ ├── ThemeTabItem.xaml │ ├── ThemeAngleBox.xaml │ ├── ThemeServerList.axaml │ ├── ThemeRandomMessage.xaml │ ├── ThemeWindow.xaml │ ├── ThemeIconLabel.xaml │ ├── ThemeDungSpinner.xaml │ ├── ThemeOverlayBox.xaml │ └── ThemeExpander.xaml ├── Utility │ ├── LocatorExt.cs │ ├── AlwaysHitTest.cs │ ├── TempFile.cs │ ├── Libc.cs │ ├── NotNullComparer.cs │ ├── Language.cs │ ├── ButtonExtensions.cs │ ├── Blake2B.cs │ ├── CollectionExtensions.cs │ ├── DynamicDataExt.cs │ └── StreamHelper.cs ├── Localization │ ├── Xaml │ │ └── GetExtension.cs │ ├── Loc.cs │ └── Language.cs ├── IconsLoader.cs ├── ViewLocator.cs ├── Api │ └── HubApi.cs ├── VcRedistCheck.cs └── App.xaml ├── SS14.Launcher.Bootstrap ├── console.bat ├── SS14.Launcher.Bootstrap.csproj └── Program.cs ├── .gitmodules ├── PublishFiles ├── SSMV.Launcher ├── SSMV.desktop └── Space Station Multiverse Launcher.app │ └── Contents │ ├── Resources │ ├── ss14.icns │ └── bin │ │ └── loader │ │ └── Space Station 14.app │ │ └── Contents │ │ ├── Resources │ │ └── ss14.icns │ │ ├── MacOS │ │ └── SS14 │ │ └── Info.plist │ ├── MacOS │ └── SS14 │ └── Info.plist ├── publish.sh ├── .gitignore ├── Assets └── info-icons │ ├── README.md │ └── github.svg ├── .editorconfig ├── testLinuxPublishBuild.sh ├── Launcher.props ├── SS14.Launcher.Tests ├── RidUtilityTest.cs ├── SS14.Launcher.Tests.csproj └── UriHelperTests.cs ├── SS14.Loader ├── MainArgs.cs ├── RedialApi.cs ├── SS14.Loader.csproj └── ZipFileApi.cs ├── .github └── workflows │ ├── build-test.yml │ └── publish-release.yml ├── SS14.Launcher.sln.DotSettings ├── publish_linux.sh ├── LICENSE.txt ├── flake.lock ├── nix └── wrapper.nix ├── publish_windows.sh ├── publish_osx.sh └── flake.nix /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /TranslationTools/.gitignore: -------------------------------------------------------------------------------- 1 | temp 2 | -------------------------------------------------------------------------------- /SS14.Launcher.FakeRobustToolbox/server/status: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.rulers": [ 3 | 120 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /SS14.Launcher.FakeRobustToolbox/README.md: -------------------------------------------------------------------------------- 1 | # Fake Robust.Client for testing 2 | 3 | 4 | -------------------------------------------------------------------------------- /SS14.Launcher.FakeRobustToolbox/server/.gitignore: -------------------------------------------------------------------------------- 1 | client.zip 2 | Robust.Client.dll 3 | 4 | -------------------------------------------------------------------------------- /SolutionFiles.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SolutionFiles.tar.gz -------------------------------------------------------------------------------- /SS14.Launcher/Assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/icon.ico -------------------------------------------------------------------------------- /SS14.Launcher/Assets/logo-long.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/logo-long.png -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0004_RaiseTime.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE FavoriteServer 2 | ADD RaiseTime DATETIME; 3 | 4 | -------------------------------------------------------------------------------- /SS14.Launcher.Bootstrap/console.bat: -------------------------------------------------------------------------------- 1 | SET DOTNET_ROOT "%CD%\dotnet" 2 | 3 | dotnet\dotnet.exe bin\SSMV.Launcher.dll 4 | 5 | PAUSE 6 | -------------------------------------------------------------------------------- /SS14.Launcher/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("SS14.Launcher.Tests")] 4 | -------------------------------------------------------------------------------- /SS14.Launcher/Assets/info-icons/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/info-icons/web.png -------------------------------------------------------------------------------- /SS14.Launcher/Assets/info-icons/wiki.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/info-icons/wiki.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Robust.LoaderApi"] 2 | path = Robust.LoaderApi 3 | url = https://github.com/space-wizards/Robust.LoaderApi.git 4 | -------------------------------------------------------------------------------- /SS14.Launcher/Assets/info-icons/discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/info-icons/discord.png -------------------------------------------------------------------------------- /SS14.Launcher/Assets/info-icons/forum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/info-icons/forum.png -------------------------------------------------------------------------------- /SS14.Launcher/Assets/info-icons/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/info-icons/github.png -------------------------------------------------------------------------------- /PublishFiles/SSMV.Launcher: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd "$(dirname "$(readlink -f "$0")")" 3 | export DOTNET_ROOT="$(pwd)/dotnet" 4 | exec ./bin/SSMV.Launcher "$@" 5 | -------------------------------------------------------------------------------- /SS14.Launcher/Global.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher; 2 | 3 | public static class Global 4 | { 5 | public const ushort DefaultServerPort = 1212; 6 | } 7 | -------------------------------------------------------------------------------- /SS14.Launcher/signing_key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MCowBQYDK2VwAyEApQ9mAhMLbmhQqRH7itgNo75S5rCSMsMXvVRmMv1d9NQ= 3 | -----END PUBLIC KEY----- 4 | 5 | -------------------------------------------------------------------------------- /SS14.Launcher.FakeRobustToolbox/SolutionFiles.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher.FakeRobustToolbox/SolutionFiles.tar.gz -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Hub.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SS14.Launcher.Models.Data; 4 | 5 | public sealed record Hub(Uri Address, long Priority); 6 | -------------------------------------------------------------------------------- /SS14.Launcher/signing_key_multiverse: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MCowBQYDK2VwAyEAM2YE9eSPVh+Z6yWGseQ8HdK4qLbwjfMd/CxlsjfQitM= 3 | -----END PUBLIC KEY----- 4 | -------------------------------------------------------------------------------- /SS14.Launcher/Assets/Fonts/noto_sans/NotoSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/Fonts/noto_sans/NotoSans-Bold.ttf -------------------------------------------------------------------------------- /SS14.Launcher/Assets/Fonts/noto_sans/NotoSans-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/Fonts/noto_sans/NotoSans-Italic.ttf -------------------------------------------------------------------------------- /SS14.Launcher/Assets/Fonts/noto_sans/NotoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/Fonts/noto_sans/NotoSans-Regular.ttf -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/InstalledEngineModule.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.Models.Data; 2 | 3 | public sealed record InstalledEngineModule(string Name, string Version); 4 | -------------------------------------------------------------------------------- /SS14.Launcher/Assets/Fonts/noto_sans/NotoSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/SS14.Launcher/Assets/Fonts/noto_sans/NotoSans-BoldItalic.ttf -------------------------------------------------------------------------------- /SS14.Launcher/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/Login/IErrorOverlayOwner.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.ViewModels.Login; 2 | 3 | public interface IErrorOverlayOwner 4 | { 5 | void OverlayOk(); 6 | } -------------------------------------------------------------------------------- /PublishFiles/SSMV.desktop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env xdg-open 2 | [Desktop Entry] 3 | Encoding=UTF-8 4 | Version=1.0 5 | Type=Application 6 | Exec=env ./SSMV.Launcher %u 7 | Name=Space Station Multiverse 8 | -------------------------------------------------------------------------------- /TranslationTools/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.rulers": [ 3 | 120 4 | ], 5 | "editor.insertSpaces": false, 6 | "editor.tabSize": 4, 7 | "editor.detectIndentation": false 8 | } 9 | -------------------------------------------------------------------------------- /PublishFiles/Space Station Multiverse Launcher.app/Contents/Resources/ss14.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/PublishFiles/Space Station Multiverse Launcher.app/Contents/Resources/ss14.icns -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0001_EngineModules.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE EngineModule ( 2 | Name TEXT NOT NULL, 3 | Version TEXT NOT NULL, 4 | 5 | CONSTRAINT NameVersion PRIMARY KEY (Name, Version) 6 | ); 7 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/OverrideAssets/Migrations/Script0001_Initial.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE OverrideAsset( 2 | Id INTEGER PRIMARY KEY, 3 | Name TEXT UNIQUE NOT NULL, 4 | OverrideName TEXT NOT NULL, 5 | Data BLOB NOT NULL 6 | ); 7 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0003_Indices.sql: -------------------------------------------------------------------------------- 1 | -- Wow I can't believe I didn't have unique indices for these. 2 | 3 | CREATE UNIQUE INDEX LoginUniqueId ON Login(UserId); 4 | CREATE UNIQUE INDEX ConfigUniqueKey ON Config(Key); 5 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/UpdateException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SS14.Launcher.Models; 4 | 5 | public sealed class UpdateException : Exception 6 | { 7 | public UpdateException(string message) : base(message) 8 | { 9 | } 10 | } -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | # Compile Translations 6 | pushd TranslationTools 7 | ./compileAllMo.sh 8 | popd 9 | 10 | # Create builds 11 | ./publish_linux.sh 12 | ./publish_osx.sh 13 | ./publish_windows.sh 14 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/ContentManagement/Migrations/Script0002_ContentIdIndex.sql: -------------------------------------------------------------------------------- 1 | -- Create an index for ContentManifest.ContentId 2 | -- Used when clearing out unused Content blobs. 3 | 4 | CREATE INDEX ContentManifest_ContentId ON ContentManifest(ContentId); 5 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0007_MVLoginMVKeyAuth.sql: -------------------------------------------------------------------------------- 1 | -- Adds key auth support 2 | 3 | CREATE TABLE "LoginMVKey" ( 4 | "UserName" TEXT NOT NULL, 5 | "PublicKey" TEXT NOT NULL, 6 | "PrivateKey" TEXT NOT NULL, 7 | PRIMARY KEY("PublicKey") 8 | ); 9 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowAge.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace SS14.Launcher.Views; 4 | 5 | public partial class MainWindowAge : UserControl 6 | { 7 | public MainWindowAge() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .idea/ 4 | *.zip 5 | *.DotSettings.user 6 | .DS_Store 7 | cmake-build* 8 | publish_test 9 | Dependencies 10 | SS14.Launcher/FodyWeavers.xsd 11 | *.mo 12 | 13 | !PublishFiles/Space Station Multiverse Launcher.app/Contents/Resources/bin/ 14 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowIdentity.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace SS14.Launcher.Views; 4 | 5 | public partial class MainWindowIdentity : UserControl 6 | { 7 | public MainWindowIdentity() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SS14.Launcher/LauncherVersion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SS14.Launcher; 4 | 5 | public static class LauncherVersion 6 | { 7 | public const string Name = "SSMV.Launcher"; 8 | public static Version? Version => typeof(LauncherVersion).Assembly.GetName().Version; 9 | } 10 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/ContentLaunchInfo.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.Models; 2 | 3 | /// 4 | /// Information loaded by the updater that we need to launch the game. 5 | /// 6 | public sealed record ContentLaunchInfo(long Version, (string Module, string Version)[] ModuleInfo); 7 | 8 | -------------------------------------------------------------------------------- /SS14.Launcher/Theme/ThemeTabItem.xaml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /PublishFiles/Space Station Multiverse Launcher.app/Contents/Resources/bin/loader/Space Station 14.app/Contents/Resources/ss14.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skyedra/SS14.Launcher/HEAD/PublishFiles/Space Station Multiverse Launcher.app/Contents/Resources/bin/loader/Space Station 14.app/Contents/Resources/ss14.icns -------------------------------------------------------------------------------- /SS14.Launcher/Models/ServerStatus/IServerSource.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.Models.ServerStatus; 2 | 3 | /// 4 | /// Where we get server status and info data from. 5 | /// 6 | public interface IServerSource 7 | { 8 | public void UpdateInfoFor(ServerStatusData statusData); 9 | } 10 | -------------------------------------------------------------------------------- /Assets/info-icons/README.md: -------------------------------------------------------------------------------- 1 | To add more icons: 2 | 3 | 1. Put SVG file here for the future 4 | 2. Put exported PNG in `SS14.Launcher/Assets/info-icons` 5 | 3. Add icon to the `ServerInfoLinkControl.ValidIcons` list in the C# code. 6 | 4. Add the icon to `IconsLoader` in the C# code to have it loaded as a resource. 7 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/ContentManagement/Migrations/Script0001_Blake2B.sql: -------------------------------------------------------------------------------- 1 | -- I changed the hash type of most things from SHA256 to BLAKE2b. 2 | -- To avoid any unforeseen problems, I'm gonna go and wipe the database here so any old SHA256 hashes get wiped. 3 | 4 | DELETE FROM ContentVersion; 5 | DELETE FROM Content; 6 | -------------------------------------------------------------------------------- /TranslationTools/compileAllMo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Loop through all PO files and compile them to .MO 4 | 5 | for po in `find ../SS14.Launcher -name 'Launcher.po' -type f` 6 | do 7 | echo $po: 8 | mo=`echo $po | sed -e 's/\.po/.mo/'` 9 | #echo $mo 10 | msgfmt --use-fuzzy "$po" -o "$mo" 11 | done 12 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/ServerFilterView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace SS14.Launcher.Views.MainWindowTabs; 4 | 5 | public sealed partial class ServerFilterView : UserControl 6 | { 7 | public ServerFilterView() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IdentityTabs/LoginTabView.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace SS14.Launcher.Views.IdentityTabs; 5 | 6 | public partial class LoginTabView : UserControl 7 | { 8 | public LoginTabView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/ExpiredLoginView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace SS14.Launcher.Views.Login; 5 | 6 | public partial class ExpiredLoginView : UserControl 7 | { 8 | public ExpiredLoginView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /TranslationTools/TranslationTools.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/DevelopmentTabView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace SS14.Launcher.Views.MainWindowTabs; 4 | 5 | public sealed partial class DevelopmentTabView : UserControl 6 | { 7 | public DevelopmentTabView() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/NewsTabView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace SS14.Launcher.Views.MainWindowTabs; 5 | 6 | public partial class NewsTabView : UserControl 7 | { 8 | public NewsTabView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /TranslationTools/.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | 4 | # Indentation and spacing 5 | indent_size = 4 6 | indent_style = tab 7 | tab_width = 4 8 | 9 | # New line preferences 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | 14 | [*.{xaml,axaml,yml,csproj,props}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | charset = utf-8 4 | 5 | # Indentation and spacing 6 | indent_size = 4 7 | indent_style = space 8 | tab_width = 4 9 | 10 | # New line preferences 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | 15 | [*.{xaml,axaml,yml,csproj,props}] 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/ServerListFiltersView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace SS14.Launcher.Views.MainWindowTabs; 4 | 5 | public sealed partial class ServerListFiltersView : UserControl 6 | { 7 | public ServerListFiltersView() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/ServerStatus/ServerStatusCode.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.Models.ServerStatus; 2 | 3 | public enum ServerStatusCode 4 | { 5 | Offline, 6 | FetchingStatus, 7 | Online 8 | } 9 | 10 | public enum ServerStatusInfoCode 11 | { 12 | NotFetched, 13 | Fetching, 14 | Error, 15 | Fetched 16 | } 17 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IdentityTabs/AlreadyMadeTabView.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace SS14.Launcher.Views.IdentityTabs; 5 | 6 | public partial class AlreadyMadeTabView : UserControl 7 | { 8 | public AlreadyMadeTabView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IdentityTabs/InformationTabView.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace SS14.Launcher.Views.IdentityTabs; 5 | 6 | public partial class InformationTabView : UserControl 7 | { 8 | public InformationTabView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowEighteenPlusInitialSetting.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace SS14.Launcher.Views; 4 | 5 | public partial class MainWindowEighteenPlusInitialSetting : UserControl 6 | { 7 | public MainWindowEighteenPlusInitialSetting() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace SS14.Launcher.Views.MainWindowTabs; 4 | 5 | public sealed partial class ServerFilterCounterView : UserControl 6 | { 7 | public ServerFilterCounterView() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/InstalledEngineVersion.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace SS14.Launcher.Models.Data; 4 | 5 | public sealed record InstalledEngineVersion( 6 | [property: JsonPropertyName("version")] 7 | string Version, 8 | [property: JsonPropertyName("signature")] 9 | string Signature); 10 | -------------------------------------------------------------------------------- /SS14.Launcher/Theme/ThemeAngleBox.xaml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/ServerListTabView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace SS14.Launcher.Views.MainWindowTabs; 5 | 6 | public partial class ServerListTabView : UserControl 7 | { 8 | public ServerListTabView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/IdentityTabs/IdentityTabViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.ViewModels.IdentityTabs; 2 | 3 | public abstract class IdentityTabViewModel : ViewModelBase 4 | { 5 | public abstract string Name { get; } 6 | 7 | public bool IsSelected { get; set; } 8 | 9 | public virtual void Selected() 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/RegisterNeedsConfirmationView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | 4 | namespace SS14.Launcher.Views.Login; 5 | 6 | public partial class RegisterNeedsConfirmationView : UserControl 7 | { 8 | public RegisterNeedsConfirmationView() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/MainWindowTabs/MainWindowTabViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.ViewModels.MainWindowTabs; 2 | 3 | public abstract class MainWindowTabViewModel : ViewModelBase 4 | { 5 | public abstract string Name { get; } 6 | 7 | public bool IsSelected { get; set; } 8 | 9 | public virtual void Selected() 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | 3 | namespace SS14.Launcher.ViewModels; 4 | 5 | public class ViewModelBase : ReactiveObject, IViewModelBase 6 | { 7 | } 8 | 9 | /// 10 | /// Signifies to that this viewmodel can be automatically located. 11 | /// 12 | public interface IViewModelBase 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/LocatorExt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Splat; 3 | 4 | namespace SS14.Launcher.Utility; 5 | 6 | public static class LocatorExt 7 | { 8 | public static T GetRequiredService(this IReadonlyDependencyResolver resolver) 9 | { 10 | return resolver.GetService() ?? throw new InvalidOperationException("Service does not exist!"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /TranslationTools/TranslationDefinition.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// Represents a unique translation entry. 3 | /// Roughly maps to: https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html 4 | /// 5 | public class TranslationDefinition 6 | { 7 | public string msgId; 8 | public string context; 9 | public List sourceReferences = new List(); 10 | } 11 | -------------------------------------------------------------------------------- /SS14.Launcher.FakeRobustToolbox/server/info: -------------------------------------------------------------------------------- 1 | { 2 | "connect_address": "udp://localhost:1212/", 3 | "auth": { 4 | "mode": "Disabled", 5 | "public_key": "" 6 | }, 7 | "build": { 8 | "engine_version": "meme", 9 | "fork_id": "custom", 10 | "version": "123", 11 | "download_url": "", 12 | "hash": null 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/LoginToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SS14.Launcher.Models; 4 | 5 | public readonly struct LoginToken 6 | { 7 | public readonly string Token; 8 | public readonly DateTimeOffset ExpireTime; 9 | 10 | public LoginToken(string token, DateTimeOffset expireTime) 11 | { 12 | Token = token; 13 | ExpireTime = expireTime; 14 | } 15 | } -------------------------------------------------------------------------------- /TranslationTools/applyTemplateChangesToAllPo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Loop through all PO files and update them with latest translations from template file 4 | 5 | template="../SS14.Launcher/Assets/locale/en_US/LC_MESSAGES/Launcher.pot" 6 | 7 | for po in `find ../SS14.Launcher -name 'Launcher.po' -type f` 8 | do 9 | echo $po: 10 | msgmerge -U --backup=none --no-fuzzy-matching "$po" "$template" 11 | done 12 | -------------------------------------------------------------------------------- /testLinuxPublishBuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Simple script for doing a publish and running it (useful for my testing) 3 | # (this is a bit inefficient, but tests exactly what someone would download) 4 | ./publish_linux.sh 5 | rm -rf ../ssmvTestPublish 6 | mkdir ../ssmvTestPublish 7 | cp SSMV.Launcher_Linux.zip ../ssmvTestPublish/ 8 | cd ../ssmvTestPublish 9 | unzip SSMV.Launcher_Linux.zip 10 | ./SSMV.Launcher 11 | -------------------------------------------------------------------------------- /SS14.Launcher/Theme/ThemeServerList.axaml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Logins/AccountLoginStatus.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.Models.Logins; 2 | 3 | public enum AccountLoginStatus 4 | { 5 | Unsure = 0, 6 | 7 | /// 8 | /// Last we checked, the login token was still valid. 9 | /// 10 | Available, 11 | 12 | /// 13 | /// The login token expired and we need the user to log in again. 14 | /// 15 | Expired 16 | } -------------------------------------------------------------------------------- /SS14.Launcher.FakeRobustToolbox/Robust.Client/Robust.Client.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | net6.0 9 | enable 10 | enable 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /SS14.Launcher/Theme/ThemeRandomMessage.xaml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /PublishFiles/Space Station Multiverse Launcher.app/Contents/MacOS/SS14: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # cd to file containing script or something? 4 | BASEDIR=$(dirname "$0") 5 | echo "$BASEDIR" 6 | cd "$BASEDIR" 7 | 8 | mkdir -p "$HOME/Library/Application Support/Space Station Multiverse" 9 | 10 | export DOTNET_ROOT="$(pwd)/../Resources/dotnet" 11 | 12 | exec ../Resources/bin/SSMV.Launcher "$@" > "$HOME/Library/Application Support/Space Station Multiverse/launcher.log" 13 | -------------------------------------------------------------------------------- /PublishFiles/Space Station Multiverse Launcher.app/Contents/Resources/bin/loader/Space Station 14.app/Contents/MacOS/SS14: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # cd to file containing script or something? 4 | BASEDIR=$(dirname "$0") 5 | echo "$BASEDIR" 6 | cd "$BASEDIR" 7 | 8 | if [[ -z ${SS14_LOG_CLIENT} ]]; then 9 | # No log path 10 | exec ../Resources/bin/SS14.Loader "$@" 11 | else 12 | exec ../Resources/bin/SS14.Loader "$@" > "$SS14_LOG_CLIENT" 2>&1 13 | fi 14 | 15 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/ContentManagement/Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SS14.Launcher.Models.ContentManagement; 4 | 5 | // Simple model classes for the content DB. 6 | 7 | public sealed class ContentVersion 8 | { 9 | public long Id; 10 | public byte[] Hash = default!; 11 | public string ForkId = default!; 12 | public string ForkVersion = default!; 13 | public DateTimeOffset LastUsed = default!; 14 | public byte[]? ZipHash; 15 | } 16 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/LoginInfoGuest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ReactiveUI; 3 | using ReactiveUI.Fody.Helpers; 4 | using SS14.Launcher.Localization; 5 | 6 | namespace SS14.Launcher.Models.Data; 7 | 8 | public class LoginInfoGuest : LoginInfo 9 | { 10 | public override string ToString() 11 | { 12 | return $"{Username} [Guest]"; 13 | } 14 | 15 | public override string LoginTypeDisplaySuffix => Loc.GetParticularString("Account Type", "Guest"); 16 | } 17 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/LoginTokenExt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SS14.Launcher.Models; 4 | 5 | public static class LoginTokenExt 6 | { 7 | public static bool IsTimeExpired(this LoginToken token) 8 | { 9 | return token.ExpireTime <= DateTimeOffset.UtcNow; 10 | } 11 | 12 | public static bool ShouldRefresh(this LoginToken token) 13 | { 14 | return token.ExpireTime <= DateTimeOffset.UtcNow + ConfigConstants.TokenRefreshThreshold; 15 | } 16 | } -------------------------------------------------------------------------------- /SS14.Launcher.FakeRobustToolbox/server/run: -------------------------------------------------------------------------------- 1 | # WARNING: This script will auto-install the engine ver. 2 | 3 | cd .. 4 | dotnet build 5 | cd server 6 | cp ../Robust.Client/bin/Debug/*/Robust.Client.dll ./ 7 | zip client.zip Robust.Client.dll 8 | echo WARNING: Copying in "meme" engine version 9 | echo You will still need to formally add the engine version into your launcher config! 10 | cp client.zip ~/".local/share/Space Station 14/launcher/engines/meme.zip" 11 | python3 -m http.server 1212 12 | 13 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/ContentManagement/ContentCompressionScheme.cs: -------------------------------------------------------------------------------- 1 | namespace SS14.Launcher.Models.ContentManagement; 2 | 3 | /// 4 | /// Compression schemes for data stored in the content database. 5 | /// 6 | public enum ContentCompressionScheme 7 | { 8 | None = 0, 9 | Deflate = 1, 10 | 11 | /// 12 | /// ZStandard compression. In the future may use SS14 specific dictionary IDs in the frame header. 13 | /// 14 | ZStd = 2, 15 | } 16 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/AlwaysHitTest.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Rendering; 4 | 5 | namespace SS14.Launcher.Utility; 6 | 7 | /// 8 | /// Utility control that always hit tests in its geometry region. 9 | /// Necessary to paper over some controls in Avalonia's default theme that have some annoying gaps otherwise. 10 | /// 11 | public sealed class AlwaysHitTest : Panel, ICustomHitTest 12 | { 13 | public bool HitTest(Point point) => true; 14 | } 15 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/MainWindowTabs/NewsEntryViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SS14.Launcher.ViewModels.MainWindowTabs; 4 | 5 | public class NewsEntryViewModel : ViewModelBase 6 | { 7 | public NewsEntryViewModel(string headline, Uri link) 8 | { 9 | Headline = headline; 10 | Link = link; 11 | } 12 | 13 | public string Headline { get; } 14 | public Uri Link { get; } 15 | 16 | public void Open() 17 | { 18 | Helpers.OpenUri(Link); 19 | } 20 | } -------------------------------------------------------------------------------- /SS14.Launcher/Views/RandomMessage.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Splat; 3 | using SS14.Launcher.Models; 4 | using SS14.Launcher.Utility; 5 | 6 | namespace SS14.Launcher.Views; 7 | 8 | public sealed partial class RandomMessage : UserControl 9 | { 10 | public RandomMessage() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | public void Refresh() 16 | { 17 | Text.Text = Locator.Current.GetRequiredService().GetRandomMessage(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/DungSpinner.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Logins/LoggedInAccount.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ReactiveUI; 3 | using SS14.Launcher.Models.Data; 4 | 5 | namespace SS14.Launcher.Models.Logins; 6 | 7 | public abstract class LoggedInAccount : ReactiveObject 8 | { 9 | public string Username => LoginInfo.Username; 10 | 11 | protected LoggedInAccount(LoginInfo loginInfo) 12 | { 13 | LoginInfo = loginInfo; 14 | } 15 | 16 | public LoginInfo LoginInfo { get; } 17 | 18 | public abstract AccountLoginStatus Status { get; } 19 | } 20 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IdentityTabs/GuestTabView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Avalonia.Controls; 4 | using Avalonia.Markup.Xaml; 5 | using ReactiveUI; 6 | using ReactiveUI.Fody.Helpers; 7 | using SS14.Launcher.Api; 8 | using SS14.Launcher.Models.Data; 9 | using SS14.Launcher.Models.Logins; 10 | 11 | namespace SS14.Launcher.Views.IdentityTabs; 12 | 13 | public partial class GuestTabView : UserControl 14 | { 15 | 16 | public GuestTabView() 17 | { 18 | InitializeComponent(); 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IdentityTabs/KeyNewTabView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Avalonia.Controls; 4 | using Avalonia.Markup.Xaml; 5 | using ReactiveUI; 6 | using ReactiveUI.Fody.Helpers; 7 | using SS14.Launcher.Api; 8 | using SS14.Launcher.Models.Data; 9 | using SS14.Launcher.Models.Logins; 10 | 11 | namespace SS14.Launcher.Views.IdentityTabs; 12 | 13 | public partial class KeyNewTabView : UserControl 14 | { 15 | 16 | public KeyNewTabView() 17 | { 18 | InitializeComponent(); 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/RandomMessage.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Launcher.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | net9.0 12 | 0.7.4.0 13 | 14 | 15 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/ConnectingOverlay.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Markup.Xaml; 3 | using SS14.Launcher.ViewModels; 4 | using Avalonia.Threading; 5 | 6 | namespace SS14.Launcher.Views; 7 | 8 | public partial class ConnectingOverlay : UserControl 9 | { 10 | public ConnectingOverlay() 11 | { 12 | InitializeComponent(); 13 | ConnectingViewModel.StartedConnecting += () => Dispatcher.UIThread.Post(() => 14 | { 15 | CancelButton.Focus(); 16 | Messages.Refresh(); 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SS14.Launcher/Theme/ThemeWindow.xaml: -------------------------------------------------------------------------------- 1 | 3 | 16 | 17 | -------------------------------------------------------------------------------- /SS14.Launcher.Tests/RidUtilityTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using SS14.Launcher.Utility; 3 | 4 | namespace SS14.Launcher.Tests; 5 | 6 | [TestFixture] 7 | [Parallelizable(ParallelScope.All)] 8 | [TestOf(typeof(RidUtility))] 9 | public sealed class RidUtilityTest 10 | { 11 | [Test] 12 | [TestCase(new[] {"win-x64", "win7"}, "win7-x64", "win7")] 13 | [TestCase(new[] {"win-x64", "win"}, "win7-x64", "win-x64")] 14 | public void TestFindBestRid(string[] rids, string start, string expected) 15 | { 16 | Assert.That(RidUtility.FindBestRid(rids, start), Is.EqualTo(expected)); 17 | } 18 | } -------------------------------------------------------------------------------- /SS14.Launcher.Tests/SS14.Launcher.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/LoginInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | using ReactiveUI; 4 | using ReactiveUI.Fody.Helpers; 5 | 6 | namespace SS14.Launcher.Models.Data; 7 | 8 | [DataContract] 9 | public abstract class LoginInfo : ReactiveObject 10 | { 11 | [Reactive] 12 | [DataMember] // (Serialize during JSON Export) 13 | public string Username { get; set; } = default!; 14 | 15 | public override string ToString() 16 | { 17 | return $"{Username} [Unknown]"; 18 | } 19 | 20 | [IgnoreDataMember] 21 | public virtual string LoginTypeDisplaySuffix => "Unknown"; 22 | } 23 | -------------------------------------------------------------------------------- /SS14.Loader/MainArgs.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Robust.LoaderApi; 3 | 4 | namespace SS14.Loader; 5 | 6 | internal sealed class MainArgs : IMainArgs 7 | { 8 | public MainArgs(string[] args, IFileApi fileApi, IRedialApi? redialApi, IEnumerable? apiMounts) 9 | { 10 | Args = args; 11 | FileApi = fileApi; 12 | RedialApi = redialApi; 13 | ApiMounts = apiMounts; 14 | } 15 | 16 | public string[] Args { get; } 17 | public IFileApi FileApi { get; } 18 | public IRedialApi? RedialApi { get; } 19 | public IEnumerable? ApiMounts { get; } 20 | } 21 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0002_ContentDB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.IO; 4 | using Microsoft.Data.Sqlite; 5 | 6 | namespace SS14.Launcher.Models.Data.Migrations; 7 | 8 | public sealed class Script0002_ContentDB : Migrator.IMigrationScript 9 | { 10 | public string Up(SqliteConnection connection) 11 | { 12 | if (Directory.Exists(LauncherPaths.DirServerContent)) 13 | Directory.Delete(LauncherPaths.DirServerContent, true); 14 | 15 | return @" 16 | DROP TABLE ServerContent; 17 | 18 | DELETE FROM Config WHERE Key='NextInstallationId'; 19 | "; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0008_MVRemoveWizDenServers.sql: -------------------------------------------------------------------------------- 1 | -- Removes wizden data / blocked wizden servers by default so as to not cause errors 2 | 3 | -- Default onto MV servers 4 | INSERT INTO ServerFilter (Category, Data) VALUES (100, 'multiverse_engine'); 5 | 6 | -- No reason to keep old wizden logins since they just throw errors at this point 7 | DELETE FROM Login; 8 | 9 | -- Remove wizden hubs 10 | DELETE FROM Hub WHERE Address="https://hub.spacestation14.com/"; 11 | DELETE FROM Hub WHERE Address="https://cdn.spacestationmultiverse.com/wizden-hub-mirror/"; 12 | DELETE FROM Hub WHERE Address="https://central.spacestation14.io/hub/"; 13 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/AuthTfaView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Input; 3 | using SS14.Launcher.ViewModels.Login; 4 | 5 | namespace SS14.Launcher.Views.Login; 6 | 7 | public sealed partial class AuthTfaView : UserControl 8 | { 9 | public AuthTfaView() 10 | { 11 | InitializeComponent(); 12 | 13 | CodeBox.KeyDown += InputBoxOnKeyDown; 14 | } 15 | 16 | private void InputBoxOnKeyDown(object? sender, KeyEventArgs e) 17 | { 18 | if (e.Key == Key.Enter && DataContext is AuthTfaViewModel vm && vm.IsInputValid) 19 | { 20 | vm.ConfirmTfa(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/TempFile.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace SS14.Launcher.Utility; 4 | 5 | public static class TempFile 6 | { 7 | public static FileStream CreateTempFile() 8 | { 9 | return new TempFileStream(Path.GetTempFileName()); 10 | } 11 | 12 | private sealed class TempFileStream : FileStream 13 | { 14 | public TempFileStream(string path) : base(path, FileMode.Open, FileAccess.ReadWrite) 15 | { 16 | } 17 | 18 | protected override void Dispose(bool disposing) 19 | { 20 | base.Dispose(disposing); 21 | 22 | File.Delete(Name); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/LanguageDropDown.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | 5 | namespace SS14.Launcher.Views; 6 | 7 | public partial class LanguageDropDown : UserControl 8 | { 9 | public static readonly StyledProperty IsDropDownOpenProperty = 10 | AvaloniaProperty.Register(nameof(IsDropDownOpen)); 11 | 12 | public bool IsDropDownOpen 13 | { 14 | get => GetValue(IsDropDownOpenProperty); 15 | set => SetValue(IsDropDownOpenProperty, value); 16 | } 17 | 18 | public LanguageDropDown() 19 | { 20 | InitializeComponent(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0005_Filters.sql: -------------------------------------------------------------------------------- 1 | -- Stores selected server filters for the server list. 2 | -- Each row is one checked filter. Maps to the ServerFilter type in C#. 3 | CREATE TABLE ServerFilter ( 4 | Category INTEGER NOT NULL, 5 | Data TEXT NOT NULL, 6 | 7 | CONSTRAINT CategoryData PRIMARY KEY (Category, Data), 8 | -- 0 isn't a valid filter category. 9 | CONSTRAINT CategoryValid CHECK (Category <> 0), 10 | -- Data probably can't be empty. 11 | CONSTRAINT DataNotEmpty CHECK (Data <> '') 12 | ); 13 | 14 | -- Set default filters up to not show 18+ servers. 15 | INSERT INTO ServerFilter (Category, Data) VALUES (4, 'false'); 16 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0006_Hubs.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE Hub ( 2 | Address TEXT NOT NULL UNIQUE PRIMARY KEY, 3 | Priority INTEGER NOT NULL UNIQUE, -- 0 is highest priority 4 | 5 | -- Address can't be empty 6 | CONSTRAINT AddressNotEmpty CHECK (Address <> ''), 7 | -- Ensure priority is >= 0 8 | CONSTRAINT PriorityNotNegative CHECK (Priority >= 0) 9 | ); 10 | 11 | -- (In multiverse, hubs are reset via c# so they only have to be managed in one location. 12 | -- So the following upstream default is not necessary here as it's included in ConfigDefaults) 13 | -- INSERT INTO Hub (Address, Priority) VALUES ('https://central.spacestation14.io/hub/', 0); 14 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/Libc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace SS14.Launcher.Utility; 5 | 6 | internal static class Libc 7 | { 8 | public const int RTLD_LAZY = 0x00001; 9 | public const int RTLD_NOW = 0x00002; 10 | public const int RTLD_BINDING_MASK = 0x3; 11 | public const int RTLD_NOLOAD = 0x00004; 12 | public const int RTLD_DEEPBIND = 0x00008; 13 | public const int RTLD_GLOBAL = 0x00100; 14 | public const int RTLD_LOCAL = 0; 15 | public const int RTLD_NODELETE = 0x01000; 16 | 17 | [DllImport("libdl.so.2")] 18 | public static extern IntPtr dlopen([MarshalAs(UnmanagedType.LPUTF8Str)] string name, int flags); 19 | } 20 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/LoginInfoAccount.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ReactiveUI; 3 | using ReactiveUI.Fody.Helpers; 4 | 5 | namespace SS14.Launcher.Models.Data; 6 | 7 | public class LoginInfoAccount : LoginInfo 8 | { 9 | [Reactive] 10 | public Guid UserId { get; set; } 11 | [Reactive] 12 | public LoginToken Token { get; set; } 13 | 14 | public enum CommonAuthServers 15 | { 16 | WizDen 17 | }; 18 | 19 | [Reactive] 20 | public string AuthServer { get; set; } 21 | 22 | public override string ToString() 23 | { 24 | return $"{Username}/{UserId} [Account]"; 25 | } 26 | 27 | public override string LoginTypeDisplaySuffix => AuthServer; 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: Build & Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | with: 16 | submodules: 'recursive' 17 | - name: Setup .NET 18 | uses: actions/setup-dotnet@v3 19 | with: 20 | dotnet-version: 9.0.x 21 | - name: Install dependencies 22 | run: dotnet restore 23 | - name: Build 24 | run: dotnet build --configuration Release --no-restore 25 | - name: SS14.Launcher.Tests 26 | run: dotnet test SS14.Launcher.Tests/SS14.Launcher.Tests.csproj -v n 27 | -------------------------------------------------------------------------------- /SS14.Launcher.FakeRobustToolbox/Robust.Client/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Robust.LoaderApi; 3 | 4 | [assembly: LoaderEntryPoint(typeof(Robust.Client.FakeClient))] 5 | 6 | namespace Robust.Client; 7 | 8 | public class FakeClient : ILoaderEntryPoint 9 | { 10 | public void Main(IMainArgs args) 11 | { 12 | var redial = args.RedialApi; 13 | if (redial == null) 14 | { 15 | Console.WriteLine("Cannot redial"); 16 | } 17 | else 18 | { 19 | Console.WriteLine("Redialling"); 20 | redial.Redial(new Uri("ss14://localhost:1212"), "Example text\nVery long example text with multiple lines."); 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /SS14.Launcher/Localization/Xaml/GetExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Data; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Markup.Xaml.MarkupExtensions; 5 | 6 | namespace SS14.Launcher.Localization.Xaml; 7 | 8 | public class GetExtension : MarkupExtension 9 | { 10 | public GetExtension(string key) 11 | { 12 | this.Key = key; 13 | } 14 | 15 | public string Key { get; set; } 16 | 17 | public string Context { get; set; } 18 | 19 | public override object ProvideValue(IServiceProvider serviceProvider) 20 | { 21 | if (Context != null) 22 | return Loc.GetParticularStringWithFallback(Context, Key); 23 | 24 | return Loc.GetString(Key); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SS14.Launcher.Bootstrap/SS14.Launcher.Bootstrap.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WinExe 6 | net45 7 | Space Station Multiverse Launcher 8 | ../SS14.Launcher/Assets/icon.ico 9 | 11 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/NotNullComparer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SS14.Launcher.Utility; 4 | 5 | /// 6 | /// Wrapper around that handles nulls for you. 7 | /// 8 | /// Type of item that is compared. 9 | public abstract class NotNullComparer : IComparer where T : notnull 10 | { 11 | public abstract int Compare(T x, T y); 12 | 13 | int IComparer.Compare(T? x, T? y) 14 | { 15 | if (ReferenceEquals(x, y)) 16 | return 0; 17 | 18 | if (ReferenceEquals(null, y)) 19 | return 1; 20 | 21 | if (ReferenceEquals(null, x)) 22 | return -1; 23 | 24 | return Compare(x, y); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/ForgotPasswordView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Input; 3 | using Avalonia.Markup.Xaml; 4 | using SS14.Launcher.ViewModels.Login; 5 | 6 | namespace SS14.Launcher.Views.Login; 7 | 8 | public sealed partial class ForgotPasswordView : UserControl 9 | { 10 | public ForgotPasswordView() 11 | { 12 | InitializeComponent(); 13 | 14 | var emailBox = this.FindControl("EmailBox"); 15 | 16 | emailBox.KeyDown += InputBoxOnKeyDown; 17 | } 18 | 19 | private void InputBoxOnKeyDown(object? sender, KeyEventArgs args) 20 | { 21 | if (args.Key == Key.Enter && DataContext is ForgotPasswordViewModel vm) 22 | { 23 | vm.SubmitPressed(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/Language.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace SS14.Launcher.Utility; 4 | 5 | public static class Language 6 | { 7 | /// 8 | /// Checks if the user's current culture or UI culture matches the given language. 9 | /// 10 | /// Two letter ISO language name, for example "ru". 11 | /// true if either the user's current culture or UI culture match the given language. 12 | public static bool UserHasLanguage(string language) 13 | { 14 | var thread = Thread.CurrentThread; 15 | 16 | return thread.CurrentCulture.TwoLetterISOLanguageName == language || 17 | thread.CurrentUICulture.TwoLetterISOLanguageName == language; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TranslationTools/EntryPoint.cs: -------------------------------------------------------------------------------- 1 | public class EntryPoint 2 | { 3 | static void Main(string[] args) 4 | { 5 | if (args.Length == 0) 6 | { 7 | Console.WriteLine("No command passed. Examples:"); 8 | Console.WriteLine("\n"); 9 | Console.WriteLine("xamlpot -- creates .pot by searching strings in xaml"); 10 | Console.WriteLine("TranslationTools xamlpot "); 11 | Console.WriteLine("TranslationTools xamlpot ../SS14.Launcher/Assets/locale/en_US/LC_MESSAGES/XamlTemp.pot ../SS14.Launcher/"); 12 | return; 13 | } 14 | 15 | // XAML => POT generator 16 | if (args[0] == "xamlpot") 17 | { 18 | var xamlPot = new XamlPot(); 19 | xamlPot.ScanDirectory(args[2]); 20 | xamlPot.ExportPot(args[1]); 21 | } 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/Migrations/Script0000_Initial.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE Login ( 2 | UserId TEXT PRIMARY KEY NOT NULL, -- GUID 3 | UserName TEXT NOT NULL, 4 | Token TEXT NOT NULL, 5 | Expires DATETIME NOT NULL 6 | ); 7 | 8 | CREATE TABLE Config ( 9 | Key TEXT PRIMARY KEY NOT NULL, 10 | Value 11 | ); 12 | 13 | CREATE TABLE FavoriteServer ( 14 | Address TEXT PRIMARY KEY NOT NULL, 15 | Name TEXT 16 | ); 17 | 18 | CREATE TABLE ServerContent ( 19 | ForkId TEXT PRIMARY KEY NOT NULL, 20 | CurrentVersion TEXT NOT NULL, 21 | CurrentHash TEXT, 22 | CurrentEngineVersion TEXT NOT NULL, 23 | DiskId INTEGER NOT NULL 24 | ); 25 | 26 | CREATE TABLE EngineInstallation ( 27 | Version TEXT PRIMARY KEY NOT NULL, 28 | Signature TEXT NOT NULL 29 | ); 30 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/ResendConfirmationView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Input; 3 | using Avalonia.Markup.Xaml; 4 | using SS14.Launcher.ViewModels.Login; 5 | 6 | namespace SS14.Launcher.Views.Login; 7 | 8 | public sealed partial class ResendConfirmationView : UserControl 9 | { 10 | public ResendConfirmationView() 11 | { 12 | InitializeComponent(); 13 | 14 | var emailBox = this.FindControl("EmailBox"); 15 | 16 | emailBox.KeyDown += InputBoxOnKeyDown; 17 | } 18 | 19 | private void InputBoxOnKeyDown(object? sender, KeyEventArgs args) 20 | { 21 | if (args.Key == Key.Enter && DataContext is ResendConfirmationViewModel vm) 22 | { 23 | vm.SubmitPressed(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/Data/LoginInfoKey.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | using System.Text.Json.Serialization; 4 | using ReactiveUI; 5 | using ReactiveUI.Fody.Helpers; 6 | using SS14.Launcher.Localization; 7 | 8 | namespace SS14.Launcher.Models.Data; 9 | 10 | [DataContract] 11 | public class LoginInfoKey : LoginInfo 12 | { 13 | [DataMember] // (Serialize during JSON Export) 14 | public string PublicKey { get; set; } = default!; 15 | 16 | [DataMember] // (Serialize during JSON Export) 17 | public string PrivateKey { get; set; } = default!; 18 | 19 | public override string ToString() 20 | { 21 | return $"{Username} [Key Auth]"; 22 | } 23 | 24 | public override string LoginTypeDisplaySuffix => Loc.GetParticularString("Account Type", "MV Key Auth"); 25 | } 26 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/Login/BaseLoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI.Fody.Helpers; 2 | using SS14.Launcher.ViewModels.IdentityTabs; 3 | 4 | namespace SS14.Launcher.ViewModels.Login; 5 | 6 | public abstract class BaseLoginViewModel : ViewModelBase, IErrorOverlayOwner 7 | { 8 | [Reactive] public bool Busy { get; protected set; } 9 | [Reactive] public string? BusyText { get; protected set; } 10 | [Reactive] public ViewModelBase? OverlayControl { get; set; } 11 | public LoginTabViewModel ParentVM { get; } 12 | 13 | protected BaseLoginViewModel(LoginTabViewModel parentVM) 14 | { 15 | ParentVM = parentVM; 16 | } 17 | 18 | public virtual void Activated() 19 | { 20 | 21 | } 22 | 23 | public virtual void OverlayOk() 24 | { 25 | OverlayControl = null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PublishFiles/Space Station Multiverse Launcher.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | SSMV 7 | CFBundleDisplayName 8 | Space Station Multiverse Launcher 9 | CFBundleExecutable 10 | SS14 11 | 17 | CFBundleIconFile 18 | ss14 19 | 20 | 21 | -------------------------------------------------------------------------------- /SS14.Launcher.Tests/UriHelperTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace SS14.Launcher.Tests; 5 | 6 | [TestFixture] 7 | [Parallelizable(ParallelScope.All)] 8 | public class UriHelperTests 9 | { 10 | [Test] 11 | [TestCase("server.spacestation14.io", "http://server.spacestation14.io:1212/status")] 12 | [TestCase("ss14s://server.spacestation14.io", "https://server.spacestation14.io/status")] 13 | [TestCase("ss14s://server.spacestation14.io:1212", "https://server.spacestation14.io:1212/status")] 14 | [TestCase("ss14s://server.spacestation14.io/foo", "https://server.spacestation14.io/foo/status")] 15 | public void GetServerStatusAddress(string input, string expected) 16 | { 17 | var uri = UriHelper.GetServerStatusAddress(input); 18 | 19 | Assert.That(uri, Is.EqualTo(new Uri(expected))); 20 | } 21 | } -------------------------------------------------------------------------------- /PublishFiles/Space Station Multiverse Launcher.app/Contents/Resources/bin/loader/Space Station 14.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | SS14LO 7 | CFBundleDisplayName 8 | Space Station 14 9 | CFBundleExecutable 10 | SS14 11 | 17 | CFBundleIconFile 18 | ss14 19 | 20 | 21 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/RegisterView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Input; 3 | using Avalonia.Markup.Xaml; 4 | using SS14.Launcher.ViewModels.Login; 5 | 6 | namespace SS14.Launcher.Views.Login; 7 | 8 | public partial class RegisterView : UserControl 9 | { 10 | public RegisterView() 11 | { 12 | InitializeComponent(); 13 | 14 | void AddKeyDown(string name) => this.FindControl(name).KeyDown += OnTextBoxKeyDown; 15 | 16 | AddKeyDown("NameBox"); 17 | AddKeyDown("EmailBox"); 18 | AddKeyDown("PasswordBox"); 19 | AddKeyDown("PasswordConfirmBox"); 20 | } 21 | 22 | private void OnTextBoxKeyDown(object? sender, KeyEventArgs args) 23 | { 24 | if (args.Key == Key.Enter && DataContext is RegisterViewModel vm) 25 | { 26 | vm.OnRegisterInButtonPressed(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/ServerFilterView.xaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/ServerInfoLinkControl.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /SS14.Launcher/Theme/ThemeIconLabel.xaml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 17 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/ServerEntryView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using Microsoft.Toolkit.Mvvm.ComponentModel; 5 | 6 | namespace SS14.Launcher.Views.MainWindowTabs; 7 | 8 | public partial class ServerEntryView : UserControl 9 | { 10 | public ServerEntryView() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) 16 | { 17 | base.OnAttachedToVisualTree(e); 18 | 19 | if (DataContext is ObservableRecipient r) 20 | r.IsActive = true; 21 | } 22 | 23 | protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) 24 | { 25 | base.OnDetachedFromVisualTree(e); 26 | 27 | if (DataContext is ObservableRecipient r) 28 | r.IsActive = false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/AuthErrorsOverlayView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Input; 4 | using Avalonia.Markup.Xaml; 5 | using SS14.Launcher.ViewModels.Login; 6 | 7 | namespace SS14.Launcher.Views.Login; 8 | 9 | public sealed partial class AuthErrorsOverlayView : UserControl, IFocusScope 10 | { 11 | public AuthErrorsOverlayView() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) 17 | { 18 | base.OnAttachedToVisualTree(e); 19 | 20 | FocusManager.Instance?.SetFocusScope(this); 21 | } 22 | 23 | protected override void OnKeyDown(KeyEventArgs e) 24 | { 25 | base.OnKeyDown(e); 26 | 27 | if (e.Key == Key.Enter && DataContext is AuthErrorsOverlayViewModel vm) 28 | { 29 | vm.Ok(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SS14.Launcher.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | GC 3 | OS 4 | VM 5 | True 6 | True 7 | True -------------------------------------------------------------------------------- /SS14.Launcher/Models/ServerStatus/IServerStatusData.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SS14.Launcher.Models.ServerStatus; 4 | 5 | /// 6 | /// Contains data about the status of a single server. 7 | /// 8 | public interface IServerStatusData : INotifyPropertyChanged 9 | { 10 | /// 11 | /// The address of the server this status is for. 12 | /// 13 | string Address { get; } 14 | 15 | /// 16 | /// The name reported by the server's status API. 17 | /// 18 | string? Name { get; set; } 19 | 20 | string? Description { get; set; } 21 | 22 | ServerStatusCode Status { get; set; } 23 | ServerStatusInfoCode StatusInfo { get; set; } 24 | 25 | int PlayerCount { get; set; } 26 | 27 | int SoftMaxPlayerCount { get; set; } 28 | string? Engine { get; set; } 29 | public string[] AuthMethods { get; set; } 30 | } 31 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/ButtonExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Avalonia.Controls; 3 | using SS14.Launcher.Localization; 4 | 5 | namespace SS14.Launcher.Utility; 6 | 7 | public static class ButtonExtensions 8 | { 9 | /// 10 | /// Sets the content of a button to a specified message ("Done!" by default) for a specified duration (2s by 11 | /// default), and disabled the button for this duration. 12 | /// 13 | public static async Task DisplayDoneMessage(this Button button, string? message = null, int duration = 2000) 14 | { 15 | if (message == null) 16 | message = Loc.GetString("Done!"); 17 | 18 | var previousContent = button.Content; 19 | button.Content = message; 20 | button.IsEnabled = false; 21 | await Task.Delay(duration); 22 | button.Content = previousContent; 23 | button.IsEnabled = true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /TranslationTools/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/TranslationTools.csproj", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | }, 16 | { 17 | "label": "publish", 18 | "command": "dotnet", 19 | "type": "process", 20 | "args": [ 21 | "publish", 22 | "${workspaceFolder}/TranslationTools.csproj", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "problemMatcher": "$msCompile" 27 | }, 28 | { 29 | "label": "watch", 30 | "command": "dotnet", 31 | "type": "process", 32 | "args": [ 33 | "watch", 34 | "run", 35 | "--project", 36 | "${workspaceFolder}/TranslationTools.csproj" 37 | ], 38 | "problemMatcher": "$msCompile" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /SS14.Launcher/IconsLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia; 3 | using Avalonia.Media.Imaging; 4 | using Avalonia.Platform; 5 | 6 | namespace SS14.Launcher; 7 | 8 | public static class IconsLoader 9 | { 10 | private static readonly (string path, string resource)[] Icons = 11 | { 12 | ("info-icons/discord.png", "InfoIcon-discord"), 13 | ("info-icons/forum.png", "InfoIcon-forum"), 14 | ("info-icons/github.png", "InfoIcon-github"), 15 | ("info-icons/web.png", "InfoIcon-web"), 16 | ("info-icons/wiki.png", "InfoIcon-wiki"), 17 | }; 18 | 19 | public static void Load(App app) 20 | { 21 | var loader = AvaloniaLocator.Current.GetService()!; 22 | 23 | foreach (var (path, resource) in Icons) 24 | { 25 | using var file = loader.Open(new Uri($"avares://SSMV.Launcher/Assets/{path}")); 26 | var bitmap = new Bitmap(file); 27 | app.Resources.Add(resource, bitmap); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewLocator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Avalonia Project. All rights reserved. 2 | // Licensed under the MIT license. See licence.md file in the project root for full license information. 3 | 4 | using System; 5 | using Avalonia.Controls; 6 | using Avalonia.Controls.Templates; 7 | using SS14.Launcher.ViewModels; 8 | 9 | namespace SS14.Launcher; 10 | 11 | public class ViewLocator : IDataTemplate 12 | { 13 | public bool SupportsRecycling => false; 14 | 15 | public IControl Build(object data) 16 | { 17 | var name = data.GetType().FullName!.Replace("ViewModel", "View"); 18 | var type = Type.GetType(name); 19 | 20 | if (type != null) 21 | { 22 | return (Control) Activator.CreateInstance(type)!; 23 | } 24 | else 25 | { 26 | return new TextBlock {Text = "Not Found: " + name}; 27 | } 28 | } 29 | 30 | public bool Match(object data) 31 | { 32 | return data is IViewModelBase; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/Blake2B.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers; 3 | using System.IO; 4 | using SpaceWizards.Sodium; 5 | 6 | namespace SS14.Launcher.Utility; 7 | 8 | public static class Blake2B 9 | { 10 | public static byte[] HashStream(Stream stream, int outputLength) 11 | { 12 | CryptoGenericHashBlake2B.State state; 13 | var pool = ArrayPool.Shared.Rent(65536); 14 | 15 | CryptoGenericHashBlake2B.Init(ref state, ReadOnlySpan.Empty, outputLength); 16 | 17 | while (true) 18 | { 19 | var read = stream.Read(pool, 0, pool.Length); 20 | if (read == 0) 21 | break; 22 | 23 | var readData = pool.AsSpan(0, read); 24 | CryptoGenericHashBlake2B.Update(ref state, readData); 25 | } 26 | 27 | ArrayPool.Shared.Return(pool); 28 | 29 | var result = new byte[outputLength]; 30 | CryptoGenericHashBlake2B.Final(ref state, result); 31 | 32 | return result; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/LoginView.xaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Input; 3 | using Avalonia.Markup.Xaml; 4 | using SS14.Launcher.ViewModels.Login; 5 | 6 | namespace SS14.Launcher.Views.Login; 7 | 8 | public partial class LoginView : UserControl 9 | { 10 | public LoginView() 11 | { 12 | InitializeComponent(); 13 | 14 | var nameBox = this.FindControl("NameBox"); 15 | var passwordBox = this.FindControl("PasswordBox"); 16 | 17 | nameBox.KeyDown += InputBoxOnKeyDown; 18 | passwordBox.KeyDown += InputBoxOnKeyDown; 19 | } 20 | 21 | private void InputBoxOnKeyDown(object? sender, KeyEventArgs args) 22 | { 23 | if (args.Key == Key.Enter && DataContext is LoginViewModel vm) 24 | { 25 | vm.OnLogInButtonPressed(); 26 | } 27 | } 28 | 29 | public void SetUnauthLoginResultText(string resultText) 30 | { 31 | this.FindControl("UnauthLoginResultText").Text = resultText; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /publish_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | ./download_net_runtime.py linux 6 | 7 | # Clear out previous build. 8 | rm -r **/bin bin/publish/Linux 9 | rm SSMV.Launcher_Linux.zip 10 | 11 | dotnet publish SS14.Launcher/SS14.Launcher.csproj /p:FullRelease=True -c Release --no-self-contained -r linux-x64 /nologo /p:RobustILLink=true 12 | dotnet publish SS14.Loader/SS14.Loader.csproj -c Release --no-self-contained -r linux-x64 /nologo 13 | 14 | # Create intermediate directories. 15 | mkdir -p bin/publish/Linux/bin 16 | mkdir -p bin/publish/Linux/bin/loader 17 | mkdir -p bin/publish/Linux/dotnet 18 | 19 | cp PublishFiles/SSMV.Launcher PublishFiles/SSMV.desktop bin/publish/Linux/ 20 | cp SS14.Launcher/bin/Release/net9.0/linux-x64/publish/* bin/publish/Linux/bin/ 21 | cp SS14.Loader/bin/Release/net9.0/linux-x64/publish/* bin/publish/Linux/bin/loader 22 | cp -r Dependencies/dotnet/linux/* bin/publish/Linux/dotnet/ 23 | cp LICENSE.txt bin/publish/Linux/ 24 | 25 | cd bin/publish/Linux 26 | zip -r ../../../SSMV.Launcher_Linux.zip * 27 | -------------------------------------------------------------------------------- /SS14.Launcher/Theme/ThemeDungSpinner.xaml: -------------------------------------------------------------------------------- 1 | 4 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /TranslationTools/updateTranslationPot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script updates the translation template file. 4 | 5 | rm -rf temp 6 | mkdir temp 7 | 8 | # Scan program .cs sources and place results into temporary file. 9 | # This does NOT include .xaml 10 | echo '' > temp/program.pot 11 | find ../SS14.Launcher -type f -iname "*.cs" | xgettext -j -f - --from-code=UTF-8 -o temp/program.pot 12 | 13 | # Scan xaml sources and place results into temporary file. 14 | dotnet run xamlpot "temp/xaml.pot" "../SS14.Launcher/" 15 | 16 | # Merge two temporary files to make one combined file 17 | xgettext -o temp/merged.pot --package-name="Space Station Multiverse Launcher" temp/program.pot temp/xaml.pot 18 | 19 | # Fix file header 20 | echo '# Space Station Multiverse Translation' > temp/final.pot 21 | echo '# Released under MIT License' >> temp/final.pot 22 | tail -n +5 temp/merged.pot >> temp/final.pot 23 | 24 | # Move into correct folder 25 | mv temp/final.pot ../SS14.Launcher/Assets/locale/en_US/LC_MESSAGES/Launcher.pot 26 | 27 | # Clean temp 28 | rm -rf temp 29 | 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2019-2023 Space Station 14 Contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /TranslationTools/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | // Use IntelliSense to find out which attributes exist for C# debugging 6 | // Use hover for the description of the existing attributes 7 | // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md 8 | "name": "Build XAML .PO", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/bin/Debug/net7.0/TranslationTools.dll", 14 | "args": [ 15 | "xamlpot", 16 | "../SS14.Launcher/Assets/locale/en_US/LC_MESSAGES/XamlTemp.pot", 17 | "../SS14.Launcher/" 18 | ], 19 | "cwd": "${workspaceFolder}", 20 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console 21 | "console": "internalConsole", 22 | "stopAtEntry": false 23 | }, 24 | { 25 | "name": ".NET Core Attach", 26 | "type": "coreclr", 27 | "request": "attach" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/CollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace SS14.Launcher.Utility; 5 | 6 | public static class CollectionExtensions 7 | { 8 | /// 9 | /// Remove an item from the list, replacing it with the one at the very end of the list. 10 | /// This means that the order will not be preserved, but it should be an O(1) operation. 11 | /// 12 | /// The list to remove from 13 | /// The index to remove 14 | /// The removed element 15 | public static T RemoveSwap(this IList list, int index) 16 | { 17 | // This method has no implementation details, 18 | // and changing the result of an operation is a breaking change. 19 | var old = list[index]; 20 | var replacement = list[^1]; 21 | list[index] = replacement; 22 | list.RemoveAt(list.Count - 1); 23 | return old; 24 | } 25 | 26 | public static bool Contains(this T[] array, T value) => Array.IndexOf(array, value) != -1; 27 | } 28 | -------------------------------------------------------------------------------- /SS14.Launcher/Utility/DynamicDataExt.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using DynamicData; 3 | 4 | namespace SS14.Launcher.Utility; 5 | 6 | public static class DynamicDataExt 7 | { 8 | public static bool TryLookup( 9 | this IObservableCache cache, 10 | TKey key, 11 | [MaybeNullWhen(false)] out TValue value) 12 | where TKey : notnull 13 | { 14 | var option = cache.Lookup(key); 15 | if (option.HasValue) 16 | { 17 | value = option.Value; 18 | return true; 19 | } 20 | 21 | value = default; 22 | return false; 23 | } 24 | 25 | public static bool TryLookup( 26 | this SourceCache cache, 27 | TKey key, 28 | [MaybeNullWhen(false)] out TValue value) 29 | where TKey : notnull 30 | { 31 | var option = cache.Lookup(key); 32 | if (option.HasValue) 33 | { 34 | value = option.Value; 35 | return true; 36 | } 37 | 38 | value = default; 39 | return false; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IdentityTabs/AlreadyMadeTabView.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/AccountDropDown.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia; 3 | using Avalonia.Controls; 4 | using Avalonia.Markup.Xaml; 5 | using SS14.Launcher.ViewModels; 6 | 7 | namespace SS14.Launcher.Views; 8 | 9 | public partial class AccountDropDown : UserControl 10 | { 11 | private AccountDropDownViewModel _viewModel; 12 | 13 | public static readonly StyledProperty IsDropDownOpenProperty = 14 | AvaloniaProperty.Register(nameof(IsDropDownOpen)); 15 | 16 | public bool IsDropDownOpen 17 | { 18 | get => GetValue(IsDropDownOpenProperty); 19 | set => SetValue(IsDropDownOpenProperty, value); 20 | } 21 | 22 | public AccountDropDown() 23 | { 24 | InitializeComponent(); 25 | } 26 | 27 | protected override void OnDataContextChanged(EventArgs e) 28 | { 29 | if (_viewModel != null) 30 | { 31 | _viewModel.Control = null; 32 | } 33 | 34 | _viewModel = DataContext as AccountDropDownViewModel; 35 | 36 | if (_viewModel != null) 37 | { 38 | _viewModel.Control = this; 39 | } 40 | 41 | base.OnDataContextChanged(e); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/IdentityTabs/AlreadyMadeTabViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using CodeHollow.FeedReader; 5 | using ReactiveUI; 6 | using SS14.Launcher.Localization; 7 | 8 | namespace SS14.Launcher.ViewModels.IdentityTabs; 9 | 10 | public class AlreadyMadeTabViewModel : IdentityTabViewModel 11 | { 12 | public AlreadyMadeTabViewModel(string name, IdentityTabViewModel replacementFor) 13 | { 14 | this._name = name; 15 | this.ReplacementFor = replacementFor; 16 | } 17 | 18 | public override void Selected() 19 | { 20 | base.Selected(); 21 | } 22 | 23 | public override string Name 24 | { 25 | get 26 | { 27 | return _name; 28 | } 29 | } 30 | private string _name; 31 | 32 | public string WelcomeText 33 | { 34 | get 35 | { 36 | return Loc.GetString(@"You've already made an account of this type. Select it at the top right."); 37 | } 38 | } 39 | 40 | /// 41 | /// What normal tab is this stub tab replacing? 42 | /// 43 | public IdentityTabViewModel ReplacementFor { get; set; } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-compat": { 4 | "flake": false, 5 | "locked": { 6 | "lastModified": 1733328505, 7 | "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", 8 | "owner": "edolstra", 9 | "repo": "flake-compat", 10 | "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", 11 | "type": "github" 12 | }, 13 | "original": { 14 | "owner": "edolstra", 15 | "repo": "flake-compat", 16 | "type": "github" 17 | } 18 | }, 19 | "nixpkgs": { 20 | "locked": { 21 | "lastModified": 1740310396, 22 | "narHash": "sha256-iqZxhCxBlzLxKxypWCJ/Aciq3OEoOjeHLrRrWvgSeHk=", 23 | "owner": "NixOS", 24 | "repo": "nixpkgs", 25 | "rev": "fe3f4eaf5fbeb29321d1165239ddc8ff985349b1", 26 | "type": "github" 27 | }, 28 | "original": { 29 | "owner": "NixOS", 30 | "ref": "release-24.11", 31 | "repo": "nixpkgs", 32 | "type": "github" 33 | } 34 | }, 35 | "root": { 36 | "inputs": { 37 | "flake-compat": "flake-compat", 38 | "nixpkgs": "nixpkgs" 39 | } 40 | } 41 | }, 42 | "root": "root", 43 | "version": 7 44 | } 45 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/ServerFilterCounterView.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IconLabel.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Primitives; 4 | using Avalonia.Controls.Templates; 5 | using Avalonia.Media; 6 | using Avalonia.Metadata; 7 | 8 | namespace SS14.Launcher.Views; 9 | 10 | public class IconLabel : TemplatedControl 11 | { 12 | public static readonly StyledProperty ContentProperty = 13 | ContentControl.ContentProperty.AddOwner(); 14 | 15 | public static readonly StyledProperty ContentTemplateProperty = 16 | ContentControl.ContentTemplateProperty.AddOwner(); 17 | 18 | public static readonly StyledProperty IconProperty = 19 | AvaloniaProperty.Register(nameof(Icon)); 20 | 21 | [Content] 22 | public object? Content 23 | { 24 | get => GetValue(ContentProperty); 25 | set => SetValue(ContentProperty, value); 26 | } 27 | 28 | public IDataTemplate? ContentTemplate 29 | { 30 | get => GetValue(ContentTemplateProperty); 31 | set => SetValue(ContentTemplateProperty, value); 32 | } 33 | 34 | public IImage Icon 35 | { 36 | get => GetValue(IconProperty); 37 | set => SetValue(IconProperty, value); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IdentityTabs/InformationTabView.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | // Use IntelliSense to find out which attributes exist for C# debugging 6 | // Use hover for the description of the existing attributes 7 | // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/SS14.Launcher/bin/Debug/net9.0/SSMV.Launcher.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/SS14.Launcher", 16 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console 17 | "console": "internalConsole", 18 | "stopAtEntry": false, 19 | "env": { 20 | "SS14_LAUNCHER_APPDATA_NAME": "Test80" 21 | } 22 | }, 23 | { 24 | "name": ".NET Core Attach", 25 | "type": "coreclr", 26 | "request": "attach" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/IdentityTabs/KeyImportTabView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Avalonia.Controls; 4 | using Avalonia.Markup.Xaml; 5 | using ReactiveUI; 6 | using ReactiveUI.Fody.Helpers; 7 | using SS14.Launcher.Api; 8 | using SS14.Launcher.Models.Data; 9 | using SS14.Launcher.Models.Logins; 10 | using SS14.Launcher.ViewModels.IdentityTabs; 11 | 12 | namespace SS14.Launcher.Views.IdentityTabs; 13 | public partial class KeyImportTabView : UserControl 14 | { 15 | private KeyImportTabViewModel _viewModel; 16 | 17 | public KeyImportTabView() 18 | { 19 | InitializeComponent(); 20 | 21 | _viewModel = (DataContext as KeyImportTabViewModel)!; // Should have been set in XAML 22 | if (_viewModel != null) 23 | { 24 | _viewModel.KeyImportTabView = this; 25 | } 26 | } 27 | 28 | protected override void OnDataContextChanged(EventArgs e) 29 | { 30 | if (_viewModel != null) 31 | { 32 | _viewModel.KeyImportTabView = null; 33 | } 34 | 35 | _viewModel = DataContext as KeyImportTabViewModel; 36 | 37 | if (_viewModel != null) 38 | { 39 | _viewModel.KeyImportTabView = this; 40 | } 41 | 42 | base.OnDataContextChanged(e); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /SS14.Loader/RedialApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Text; 6 | using System.Linq; 7 | using Robust.LoaderApi; 8 | 9 | namespace SS14.Loader; 10 | 11 | internal sealed class RedialApi : IRedialApi 12 | { 13 | private readonly string _launcher; 14 | 15 | public RedialApi(string launcher) 16 | { 17 | _launcher = launcher; 18 | } 19 | 20 | public void Redial(Uri uri, string text = "") 21 | { 22 | var reasonCommand = "R" + Convert.ToHexString(Encoding.UTF8.GetBytes(text)); 23 | var connectCommand = "C" + Convert.ToHexString(Encoding.UTF8.GetBytes(uri.ToString())); 24 | 25 | var startInfo = new ProcessStartInfo 26 | { 27 | FileName = _launcher, 28 | UseShellExecute = false, 29 | ArgumentList = 30 | { 31 | "--commands", 32 | ":RedialWait", 33 | reasonCommand, 34 | connectCommand 35 | } 36 | }; 37 | 38 | startInfo.EnvironmentVariables.Remove("DOTNET_TieredPGO"); 39 | startInfo.EnvironmentVariables.Remove("DOTNET_TC_QuickJitForLoops"); 40 | startInfo.EnvironmentVariables.Remove("DOTNET_ReadyToRun"); 41 | 42 | Process.Start(startInfo); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /SS14.Launcher/Localization/Loc.cs: -------------------------------------------------------------------------------- 1 | using Splat; 2 | using SS14.Launcher.Utility; 3 | 4 | namespace SS14.Launcher.Localization; 5 | 6 | /// 7 | /// Shortcut class for convenience (wraps LocalizationManager) 8 | /// /// 9 | public static class Loc 10 | { 11 | private static LocalizationManager localizationManager => Locator.Current.GetRequiredService(); 12 | 13 | public static string GetString(string sourceString) 14 | { 15 | return localizationManager.GetString(sourceString); 16 | } 17 | 18 | public static string GetString(string sourceString, params object[] args) 19 | { 20 | return localizationManager.GetString(sourceString, args); 21 | } 22 | 23 | public static string GetParticularString(string context, string sourceString) 24 | { 25 | return localizationManager.GetParticularString(context, sourceString); 26 | } 27 | 28 | public static string GetParticularString(string context, string sourceString, params object[] args) 29 | { 30 | return localizationManager.GetParticularString(context, sourceString, args); 31 | } 32 | 33 | public static string GetParticularStringWithFallback(string context, string sourceString) 34 | { 35 | return localizationManager.GetParticularStringWithFallback(context, sourceString); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/SS14.Launcher/SS14.Launcher.csproj", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | }, 16 | { 17 | "label": "publish", 18 | "command": "dotnet", 19 | "type": "process", 20 | "args": [ 21 | "publish", 22 | "${workspaceFolder}/SS14.Launcher/SS14.Launcher.csproj", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "problemMatcher": "$msCompile" 27 | }, 28 | { 29 | "label": "watch", 30 | "command": "dotnet", 31 | "type": "process", 32 | "args": [ 33 | "watch", 34 | "run", 35 | "--project", 36 | "${workspaceFolder}/SS14.Launcher/SS14.Launcher.csproj" 37 | ], 38 | "problemMatcher": "$msCompile" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /SS14.Launcher/Views/DirectConnectDialog.xaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 17 | 18 | 19 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/MainWindowTabs/DevelopmentTabViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | using Splat; 3 | using SS14.Launcher.Models.Data; 4 | using SS14.Launcher.Utility; 5 | 6 | namespace SS14.Launcher.ViewModels.MainWindowTabs; 7 | 8 | public sealed class DevelopmentTabViewModel : MainWindowTabViewModel 9 | { 10 | public DataManager Cfg { get; } 11 | 12 | public DevelopmentTabViewModel() 13 | { 14 | Cfg = Locator.Current.GetRequiredService(); 15 | 16 | // TODO: This sucks and leaks. 17 | Cfg.GetCVarEntry(CVars.EngineOverrideEnabled).PropertyChanged += (sender, args) => 18 | { 19 | this.RaisePropertyChanged(nameof(Name)); 20 | }; 21 | } 22 | 23 | public override string Name => Cfg.GetCVar(CVars.EngineOverrideEnabled) ? "[DEV (override active!!!)]" : "[DEV]"; 24 | 25 | public bool DisableSigning 26 | { 27 | get => Cfg.GetCVar(CVars.DisableSigning); 28 | set 29 | { 30 | Cfg.SetCVar(CVars.DisableSigning, value); 31 | Cfg.CommitConfig(); 32 | } 33 | } 34 | 35 | public bool EngineOverrideEnabled 36 | { 37 | get => Cfg.GetCVar(CVars.EngineOverrideEnabled); 38 | set 39 | { 40 | Cfg.SetCVar(CVars.EngineOverrideEnabled, value); 41 | Cfg.CommitConfig(); 42 | } 43 | } 44 | 45 | public string EngineOverridePath 46 | { 47 | get => Cfg.GetCVar(CVars.EngineOverridePath); 48 | set 49 | { 50 | Cfg.SetCVar(CVars.EngineOverridePath, value); 51 | Cfg.CommitConfig(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/MainWindowTabs/DevelopmentTabView.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | Disable Engine Signature Checks 15 | 18 | 19 | 20 | Enable engine override 21 | 22 | 23 | 24 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /SS14.Launcher/VcRedistCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | using TerraFX.Interop.Windows; 5 | 6 | namespace SS14.Launcher; 7 | 8 | // Checks that the VC++ 2015 redist, which the game needs, is present. 9 | public static class VcRedistCheck 10 | { 11 | public static unsafe void Check() 12 | { 13 | if (!OperatingSystem.IsWindows()) 14 | return; 15 | 16 | // ReSharper disable once StringLiteralTypo 17 | if (NativeLibrary.TryLoad("VCRUNTIME140.dll", out var lib)) 18 | { 19 | // VC++ 2015 runtime present, we're good. 20 | // Unload the library I guess since we don't need it. 21 | NativeLibrary.Free(lib); 22 | 23 | return; 24 | } 25 | 26 | // We could show this dialog all fancy with Avalonia but I'm lazy so. 27 | int ret; 28 | 29 | var text = "The game needs the VC++ 2015 redistributable installed, which you do not have.\nWould you like to download the installer for it?"; 30 | var caption = "VC++ 2015 redistributable not installed"; 31 | uint type = MB.MB_ICONERROR | MB.MB_YESNO; 32 | { 33 | { 34 | ret = Helpers.MessageBoxHelper(text, caption, type); 35 | } 36 | } 37 | 38 | if (ret == Windows.IDYES) 39 | { 40 | Process.Start(new ProcessStartInfo 41 | { 42 | FileName = "https://aka.ms/vs/16/release/vc_redist.x64.exe", 43 | UseShellExecute = true 44 | })! 45 | .WaitForExit(); 46 | } 47 | 48 | Environment.Exit(1); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /SS14.Launcher/ViewModels/MainWindowTabs/ServerFilterViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Mvvm.ComponentModel; 2 | using SS14.Launcher.Models.Data; 3 | using SS14.Launcher.Utility; 4 | 5 | namespace SS14.Launcher.ViewModels.MainWindowTabs; 6 | 7 | public class ServerFilterViewModel : ObservableObject 8 | { 9 | public ServerFilter Filter { get; } 10 | protected readonly ServerListFiltersViewModel Parent; 11 | 12 | public string Name { get; } 13 | public string ShortName { get; } 14 | 15 | public bool Selected 16 | { 17 | get => Parent.GetFilter(Filter); 18 | set 19 | { 20 | Parent.SetFilter(Filter, value); 21 | OnPropertyChanged(); 22 | } 23 | } 24 | 25 | public ServerFilterViewModel( 26 | string name, 27 | string shortName, 28 | ServerFilter filter, 29 | ServerListFiltersViewModel parent) 30 | { 31 | Filter = filter; 32 | Parent = parent; 33 | Name = name; 34 | ShortName = shortName; 35 | } 36 | } 37 | 38 | public sealed class ServerFilterCounterViewModel : ServerFilterViewModel 39 | { 40 | public ICVarEntry CVar { get; } 41 | 42 | public int CounterValue 43 | { 44 | get => CVar.Value; 45 | set 46 | { 47 | CVar.Value = value; 48 | Parent.CounterUpdated(); 49 | } 50 | } 51 | 52 | public ServerFilterCounterViewModel( 53 | string name, 54 | string shortName, 55 | ServerFilter filter, 56 | ICVarEntry cVar, 57 | ServerListFiltersViewModel parent) : base(name, shortName, filter, parent) 58 | { 59 | CVar = cVar; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/AddFavoriteDialog.xaml: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Pulling news... 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/Login/ForgotPasswordView.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 19 | 20 | 22 | 23 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /SS14.Launcher/Models/ServerInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace SS14.Launcher.Models; 4 | 5 | /// 6 | /// Basic data type to deserialize from the /info API endpoint on the server. 7 | /// 8 | public sealed class ServerInfo 9 | { 10 | [JsonPropertyName("connect_address")] 11 | public string? ConnectAddress { get; set; } 12 | 13 | [JsonInclude, JsonPropertyName("build")] public ServerBuildInformation? BuildInformation; 14 | [JsonPropertyName("auth")] public ServerAuthInformation AuthInformation { get; set; } = default!; 15 | 16 | [JsonPropertyName("desc")] public string? Desc { get; set; } 17 | [JsonPropertyName("links")] public ServerInfoLink[]? Links { get; set; } 18 | } 19 | 20 | public sealed record ServerInfoLink(string Name, string? Icon, string Url); 21 | 22 | public class ServerAuthInformation 23 | { 24 | [JsonPropertyName("mode")] public AuthMode Mode { get; set; } 25 | 26 | [JsonPropertyName("public_key")] 27 | public string PublicKey { get; set; } = default!; 28 | } 29 | 30 | public class ServerBuildInformation 31 | { 32 | [JsonInclude, JsonPropertyName("download_url")] 33 | public string? DownloadUrl = default!; 34 | 35 | [JsonInclude, JsonPropertyName("manifest_url")] 36 | public string? ManifestUrl; 37 | 38 | [JsonInclude, JsonPropertyName("manifest_download_url")] 39 | public string? ManifestDownloadUrl; 40 | 41 | [JsonInclude, JsonPropertyName("engine_version")] 42 | public string EngineVersion = default!; 43 | 44 | [JsonInclude, JsonPropertyName("version")] 45 | public string Version = default!; 46 | 47 | [JsonInclude, JsonPropertyName("fork_id")] 48 | public string ForkId = default!; 49 | 50 | [JsonInclude, JsonPropertyName("hash")] 51 | public string? Hash; 52 | 53 | [JsonInclude, JsonPropertyName("manifest_hash")] 54 | public string? ManifestHash; 55 | 56 | [JsonInclude, JsonPropertyName("acz")] 57 | public bool Acz; 58 | } 59 | 60 | [JsonConverter(typeof(JsonStringEnumConverter))] 61 | public enum AuthMode 62 | { 63 | Optional = 0, 64 | Required = 1, 65 | Disabled = 2 66 | } 67 | -------------------------------------------------------------------------------- /SS14.Launcher/Views/LanguageDropDown.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | --------------------------------------------------------------------------------