├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yaml
│ └── feature_request.yaml
├── dependabot.yml
└── workflows
│ ├── ci-debug.yml
│ ├── ci-release.yml
│ └── winget.yml
├── .gitignore
├── .gitmodules
├── Bloxstrap.sln
├── Bloxstrap
├── App.xaml
├── App.xaml.cs
├── AppData
│ ├── CommonAppData.cs
│ ├── IAppData.cs
│ ├── RobloxPlayerData.cs
│ └── RobloxStudioData.cs
├── AssemblyInfo.cs
├── Bloxstrap.csproj
├── Bloxstrap.ico
├── Bootstrapper.cs
├── Enums
│ ├── BootstrapperIcon.cs
│ ├── BootstrapperStyle.cs
│ ├── CursorType.cs
│ ├── CustomThemeTemplate.cs
│ ├── EmojiType.cs
│ ├── ErrorCode.cs
│ ├── FlagPresets
│ │ ├── InGameMenuVersion.cs
│ │ ├── LightingMode.cs
│ │ ├── MSAAMode.cs
│ │ ├── RenderingMode.cs
│ │ └── TextureQuality.cs
│ ├── GenericTriState.cs
│ ├── LaunchMode.cs
│ ├── NextAction.cs
│ ├── ServerType.cs
│ ├── Theme.cs
│ ├── VersionComparison.cs
│ └── WebEnvironment.cs
├── Exceptions
│ ├── AssertionException.cs
│ ├── ChecksumFailedException.cs
│ ├── CustomThemeException.cs
│ ├── InvalidChannelException.cs
│ └── InvalidHTTPResponseException.cs
├── Extensions
│ ├── BootstrapperIconEx.cs
│ ├── BootstrapperStyleEx.cs
│ ├── CustomThemeTemplateEx.cs
│ ├── DateTimeEx.cs
│ ├── EmojiTypeEx.cs
│ ├── HttpClientEx.cs
│ ├── IconEx.cs
│ ├── RegistryKeyEx.cs
│ ├── ResourceManagerEx.cs
│ ├── ServerTypeEx.cs
│ ├── TEnumEx.cs
│ └── ThemeEx.cs
├── FastFlagManager.cs
├── GlobalCache.cs
├── GlobalUsings.cs
├── HttpClientLoggingHandler.cs
├── Installer.cs
├── Integrations
│ ├── ActivityWatcher.cs
│ └── DiscordRichPresence.cs
├── JsonManager.cs
├── LaunchHandler.cs
├── LaunchSettings.cs
├── Locale.cs
├── Logger.cs
├── Models
│ ├── APIs
│ │ ├── Config
│ │ │ ├── Supporter.cs
│ │ │ ├── SupporterData.cs
│ │ │ └── SupporterGroup.cs
│ │ ├── GitHub
│ │ │ ├── GitHubReleaseAsset.cs
│ │ │ └── GithubRelease.cs
│ │ ├── IPInfoResponse.cs
│ │ └── Roblox
│ │ │ ├── ApiArrayResponse.cs
│ │ │ ├── ClientFlagSettings.cs
│ │ │ ├── ClientVersion.cs
│ │ │ ├── GameCreator.cs
│ │ │ ├── GameDetailResponse.cs
│ │ │ ├── GetUserResponse.cs
│ │ │ ├── ThumbnailBatchResponse.cs
│ │ │ ├── ThumbnailRequest.cs
│ │ │ ├── ThumbnailResponse.cs
│ │ │ └── UniverseIdResponse.cs
│ ├── Attributes
│ │ ├── BuildMetadataAttribute.cs
│ │ ├── EnumNameAttribute.cs
│ │ └── EnumSortAttribute.cs
│ ├── BloxstrapRPC
│ │ ├── Message.cs
│ │ ├── RichPresence.cs
│ │ └── RichPresenceImage.cs
│ ├── BootstrapperIconEntry.cs
│ ├── CustomIntegration.cs
│ ├── DeployInfo.cs
│ ├── Entities
│ │ ├── ActivityData.cs
│ │ ├── ModPresetFileData.cs
│ │ ├── UniverseDetails.cs
│ │ └── UserDetails.cs
│ ├── FastFlag.cs
│ ├── FontFace.cs
│ ├── FontFamily.cs
│ ├── LaunchFlag.cs
│ ├── Manifest
│ │ ├── FileManifest.cs
│ │ ├── ManifestFile.cs
│ │ ├── Package.cs
│ │ └── PackageManifest.cs
│ ├── Persistable
│ │ ├── AppState.cs
│ │ ├── RobloxState.cs
│ │ ├── Settings.cs
│ │ ├── State.cs
│ │ └── WindowState.cs
│ ├── SettingTasks
│ │ ├── Base
│ │ │ ├── BaseTask.cs
│ │ │ ├── BoolBaseTask.cs
│ │ │ ├── EnumBaseTask.cs
│ │ │ └── StringBaseTask.cs
│ │ ├── EmojiModPresetTask.cs
│ │ ├── EnumModPresetTask.cs
│ │ ├── ExtractIconsTask.cs
│ │ ├── FontModPresetTask.cs
│ │ ├── ModPresetTask.cs
│ │ └── ShortcutTask.cs
│ ├── ThumbnailCacheEntry.cs
│ └── WatcherData.cs
├── MultiInstanceWatcher.cs
├── NativeMethods.txt
├── Paths.cs
├── Properties
│ ├── PublishProfiles
│ │ └── Publish-x64.pubxml
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ ├── Settings.settings
│ └── launchSettings.json
├── Resource.cs
├── Resources
│ ├── BootstrapperStyles
│ │ └── ByfronDialog
│ │ │ ├── ByfronLogoDark.jpg
│ │ │ ├── ByfronLogoLight.jpg
│ │ │ └── Matt.png
│ ├── CancelButton.png
│ ├── CancelButtonHover.png
│ ├── CustomBootstrapperSchema.json
│ ├── CustomBootstrapperTemplate_Blank.xml
│ ├── CustomBootstrapperTemplate_Simple.xml
│ ├── DarkCancelButton.png
│ ├── DarkCancelButtonHover.png
│ ├── Fonts
│ │ ├── NotoSansThai-VariableFont_wdth,wght.ttf
│ │ └── Rubik-VariableFont_wght.ttf
│ ├── Icon2008.ico
│ ├── Icon2011.ico
│ ├── Icon2017.ico
│ ├── Icon2019.ico
│ ├── Icon2022.ico
│ ├── IconBloxstrap.ico
│ ├── IconBloxstrapClassic.ico
│ ├── IconEarly2015.ico
│ ├── IconLate2015.ico
│ ├── MessageBox
│ │ ├── Error.png
│ │ ├── FullQuality
│ │ │ ├── Error.png
│ │ │ ├── Information.png
│ │ │ ├── Question.png
│ │ │ └── Warning.png
│ │ ├── Information.png
│ │ ├── Question.png
│ │ └── Warning.png
│ ├── Mods
│ │ ├── Cursor
│ │ │ ├── From2006
│ │ │ │ ├── ArrowCursor.png
│ │ │ │ └── ArrowFarCursor.png
│ │ │ └── From2013
│ │ │ │ ├── ArrowCursor.png
│ │ │ │ └── ArrowFarCursor.png
│ │ ├── OldAvatarBackground.rbxl
│ │ └── Sounds
│ │ │ ├── Empty.mp3
│ │ │ ├── OldDeath.ogg
│ │ │ ├── OldGetUp.mp3
│ │ │ ├── OldJump.mp3
│ │ │ └── OldWalk.mp3
│ ├── Strings.Designer.cs
│ ├── Strings.ar.resx
│ ├── Strings.bg.resx
│ ├── Strings.bs.resx
│ ├── Strings.cs.resx
│ ├── Strings.da.resx
│ ├── Strings.de.resx
│ ├── Strings.en-US.resx
│ ├── Strings.es-ES.resx
│ ├── Strings.fa.resx
│ ├── Strings.fi.resx
│ ├── Strings.fil.resx
│ ├── Strings.fr.resx
│ ├── Strings.hr.resx
│ ├── Strings.hu.resx
│ ├── Strings.id.resx
│ ├── Strings.it.resx
│ ├── Strings.ja.resx
│ ├── Strings.ko.resx
│ ├── Strings.lt.resx
│ ├── Strings.lv.resx
│ ├── Strings.ms.resx
│ ├── Strings.nl.resx
│ ├── Strings.pl.resx
│ ├── Strings.pt-BR.resx
│ ├── Strings.resx
│ ├── Strings.ro.resx
│ ├── Strings.ru.resx
│ ├── Strings.sv-SE.resx
│ ├── Strings.th.resx
│ ├── Strings.tr.resx
│ ├── Strings.uk.resx
│ ├── Strings.vi.resx
│ ├── Strings.zh-CN.resx
│ ├── Strings.zh-HK.resx
│ └── Strings.zh-TW.resx
├── RobloxInterfaces
│ ├── ApplicationSettings.cs
│ └── Deployment.cs
├── UI
│ ├── Converters
│ │ ├── EnumNameConverter.cs
│ │ ├── RangeConverter.cs
│ │ └── StringFormatConverter.cs
│ ├── Elements
│ │ ├── About
│ │ │ ├── MainWindow.xaml
│ │ │ ├── MainWindow.xaml.cs
│ │ │ └── Pages
│ │ │ │ ├── AboutPage.xaml
│ │ │ │ ├── AboutPage.xaml.cs
│ │ │ │ ├── LicensesPage.xaml
│ │ │ │ ├── LicensesPage.xaml.cs
│ │ │ │ ├── SupportersPage.xaml
│ │ │ │ ├── SupportersPage.xaml.cs
│ │ │ │ ├── TranslatorsPage.xaml
│ │ │ │ └── TranslatorsPage.xaml.cs
│ │ ├── Base
│ │ │ └── WpfUiWindow.cs
│ │ ├── Bootstrapper
│ │ │ ├── Base
│ │ │ │ ├── BaseFunctions.cs
│ │ │ │ └── WinFormsDialogBase.cs
│ │ │ ├── ByfronDialog.xaml
│ │ │ ├── ByfronDialog.xaml.cs
│ │ │ ├── ClassicFluentDialog.xaml
│ │ │ ├── ClassicFluentDialog.xaml.cs
│ │ │ ├── CustomDialog.Converters.cs
│ │ │ ├── CustomDialog.Creator.cs
│ │ │ ├── CustomDialog.Elements.cs
│ │ │ ├── CustomDialog.Utilities.cs
│ │ │ ├── CustomDialog.xaml
│ │ │ ├── CustomDialog.xaml.cs
│ │ │ ├── FluentDialog.xaml
│ │ │ ├── FluentDialog.xaml.cs
│ │ │ ├── LegacyDialog2008.Designer.cs
│ │ │ ├── LegacyDialog2008.cs
│ │ │ ├── LegacyDialog2008.resx
│ │ │ ├── LegacyDialog2011.Designer.cs
│ │ │ ├── LegacyDialog2011.cs
│ │ │ ├── LegacyDialog2011.resx
│ │ │ ├── ProgressDialog.Designer.cs
│ │ │ ├── ProgressDialog.cs
│ │ │ ├── ProgressDialog.resx
│ │ │ ├── VistaDialog.Designer.cs
│ │ │ ├── VistaDialog.cs
│ │ │ └── VistaDialog.resx
│ │ ├── ContextMenu
│ │ │ ├── MenuContainer.xaml
│ │ │ ├── MenuContainer.xaml.cs
│ │ │ ├── ServerHistory.xaml
│ │ │ ├── ServerHistory.xaml.cs
│ │ │ ├── ServerInformation.xaml
│ │ │ └── ServerInformation.xaml.cs
│ │ ├── Controls
│ │ │ ├── Expander.xaml
│ │ │ ├── Expander.xaml.cs
│ │ │ ├── MarkdownTextBlock.cs
│ │ │ ├── OptionControl.xaml
│ │ │ └── OptionControl.xaml.cs
│ │ ├── Dialogs
│ │ │ ├── AddCustomThemeDialog.xaml
│ │ │ ├── AddCustomThemeDialog.xaml.cs
│ │ │ ├── AddFastFlagDialog.xaml
│ │ │ ├── AddFastFlagDialog.xaml.cs
│ │ │ ├── ConnectivityDialog.xaml
│ │ │ ├── ConnectivityDialog.xaml.cs
│ │ │ ├── ExceptionDialog.xaml
│ │ │ ├── ExceptionDialog.xaml.cs
│ │ │ ├── FluentMessageBox.xaml
│ │ │ ├── FluentMessageBox.xaml.cs
│ │ │ ├── LanguageSelectorDialog.xaml
│ │ │ ├── LanguageSelectorDialog.xaml.cs
│ │ │ ├── LaunchMenuDialog.xaml
│ │ │ ├── LaunchMenuDialog.xaml.cs
│ │ │ ├── UninstallerDialog.xaml
│ │ │ └── UninstallerDialog.xaml.cs
│ │ ├── Editor
│ │ │ ├── BootstrapperEditorWindow.xaml
│ │ │ └── BootstrapperEditorWindow.xaml.cs
│ │ ├── Installer
│ │ │ ├── MainWindow.xaml
│ │ │ ├── MainWindow.xaml.cs
│ │ │ └── Pages
│ │ │ │ ├── CompletionPage.xaml
│ │ │ │ ├── CompletionPage.xaml.cs
│ │ │ │ ├── InstallPage.xaml
│ │ │ │ ├── InstallPage.xaml.cs
│ │ │ │ ├── WelcomePage.xaml
│ │ │ │ └── WelcomePage.xaml.cs
│ │ └── Settings
│ │ │ ├── MainWindow.xaml
│ │ │ ├── MainWindow.xaml.cs
│ │ │ └── Pages
│ │ │ ├── AppearancePage.xaml
│ │ │ ├── AppearancePage.xaml.cs
│ │ │ ├── BloxstrapPage.xaml
│ │ │ ├── BloxstrapPage.xaml.cs
│ │ │ ├── BootstrapperPage.xaml
│ │ │ ├── BootstrapperPage.xaml.cs
│ │ │ ├── FastFlagEditorPage.xaml
│ │ │ ├── FastFlagEditorPage.xaml.cs
│ │ │ ├── FastFlagEditorWarningPage.xaml
│ │ │ ├── FastFlagEditorWarningPage.xaml.cs
│ │ │ ├── FastFlagsPage.xaml
│ │ │ ├── FastFlagsPage.xaml.cs
│ │ │ ├── IntegrationsPage.xaml
│ │ │ ├── IntegrationsPage.xaml.cs
│ │ │ ├── ModsPage.xaml
│ │ │ ├── ModsPage.xaml.cs
│ │ │ ├── ShortcutsPage.xaml
│ │ │ └── ShortcutsPage.xaml.cs
│ ├── Frontend.cs
│ ├── IBootstrapperDialog.cs
│ ├── NotifyIconWrapper.cs
│ ├── Style
│ │ ├── Dark.xaml
│ │ ├── Default.xaml
│ │ ├── Editor-Theme-Dark.xshd
│ │ ├── Editor-Theme-Light.xshd
│ │ └── Light.xaml
│ ├── Utility
│ │ ├── Rendering.cs
│ │ ├── TaskbarProgress.cs
│ │ └── WindowScaling.cs
│ └── ViewModels
│ │ ├── About
│ │ ├── AboutViewModel.cs
│ │ └── SupportersViewModel.cs
│ │ ├── Bootstrapper
│ │ ├── BootstrapperDialogViewModel.cs
│ │ ├── ByfronDialogViewModel.cs
│ │ ├── ClassicFluentDialogViewModel.cs
│ │ └── FluentDialogViewModel.cs
│ │ ├── ContextMenu
│ │ ├── ServerHistoryViewModel.cs
│ │ └── ServerInformationViewModel.cs
│ │ ├── Dialogs
│ │ ├── AddCustomThemeViewModel.cs
│ │ ├── LanguageSelectorViewModel.cs
│ │ ├── LaunchMenuViewModel.cs
│ │ └── UninstallerViewModel.cs
│ │ ├── Editor
│ │ └── BootstrapperEditorWindowViewModel.cs
│ │ ├── GlobalViewModel.cs
│ │ ├── Installer
│ │ ├── CompletionViewModel.cs
│ │ ├── InstallViewModel.cs
│ │ ├── MainWindowViewModel.cs
│ │ └── WelcomeViewModel.cs
│ │ ├── NotifyPropertyChangedViewModel.cs
│ │ └── Settings
│ │ ├── AppearanceViewModel.cs
│ │ ├── BehaviourViewModel.cs
│ │ ├── BloxstrapViewModel.cs
│ │ ├── FastFlagEditorWarningViewModel.cs
│ │ ├── FastFlagsViewModel.cs
│ │ ├── IntegrationsViewModel.cs
│ │ ├── MainWindowViewModel.cs
│ │ ├── ModsViewModel.cs
│ │ └── ShortcutsViewModel.cs
├── Utilities.cs
├── Utility
│ ├── AsyncMutex.cs
│ ├── Filesystem.cs
│ ├── FixedCapacityList.cs
│ ├── Http.cs
│ ├── InterProcessLock.cs
│ ├── MD5Hash.cs
│ ├── PathValidator.cs
│ ├── Shortcut.cs
│ ├── Thumbnails.cs
│ └── WindowsRegistry.cs
├── Watcher.cs
└── app.manifest
├── Images
├── Bloxstrap-full-dark.png
├── Bloxstrap-full-light.png
└── Bloxstrap.png
├── LICENSE
├── README.md
└── Scripts
└── Translations
├── find-unused.py
└── prep.py
/.github/ISSUE_TEMPLATE/feature_request.yaml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | title: "[REQ] "
3 | description: Suggest a feature that should be added
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | ### **Preliminary instructions**
9 | - Please first check to see if your idea has already been suggested. You can check by [searching all previous issues](https://github.com/pizzaboxer/bloxstrap/issues?q=is%3Aissue).
10 | - If your feature suggestion is to do with Roblox itself, please consider that what's possible is heavily constrained by what [FastFlags](https://github.com/pizzaboxer/bloxstrap/wiki/A-guide-to-FastFlags) are available.
11 | - Don't ask for support on Linux or Mac. That's not happening anytime soon, sorry.
12 | - type: checkboxes
13 | id: terms
14 | attributes:
15 | label: Acknowledgement of preliminary instructions
16 | options:
17 | - label: I have read and acknowledged the preliminary instructions.
18 | required: true
19 | - type: textarea
20 | id: what-happened
21 | attributes:
22 | label: What idea do you have?
23 | description: Provide a comprehensive description of what you think can be improved!
24 | validations:
25 | required: true
26 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 | - package-ecosystem: "nuget"
8 | directory: "/"
9 | schedule:
10 | interval: "daily"
11 | - package-ecosystem: "gitsubmodule"
12 | directory: "/"
13 | schedule:
14 | interval: "daily"
15 |
--------------------------------------------------------------------------------
/.github/workflows/ci-debug.yml:
--------------------------------------------------------------------------------
1 | name: CI (Debug)
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | build:
6 | runs-on: windows-latest
7 |
8 | steps:
9 | - uses: actions/checkout@v4
10 | with:
11 | submodules: true
12 |
13 | - uses: actions/setup-dotnet@v4
14 | with:
15 | dotnet-version: '6.0.x'
16 |
17 | - name: Restore dependencies
18 | run: dotnet restore
19 |
20 | - name: Build
21 | run: dotnet build --no-restore
22 |
23 | - name: Publish
24 | run: dotnet publish -p:PublishSingleFile=true -p:CommitHash=${{ github.sha }} -p:CommitRef=${{ github.ref_type }}/${{ github.ref_name }} -r win-x64 -c Debug --self-contained false .\Bloxstrap\Bloxstrap.csproj
25 |
26 | - name: Upload Artifact
27 | uses: actions/upload-artifact@v4
28 | with:
29 | name: Bloxstrap (Debug) (${{ github.sha }})
30 | path: .\Bloxstrap\bin\Debug\net6.0-windows\win-x64\publish\*
--------------------------------------------------------------------------------
/.github/workflows/winget.yml:
--------------------------------------------------------------------------------
1 | name: Publish to Winget
2 |
3 | on:
4 | release:
5 | types: [released]
6 |
7 | jobs:
8 | publish:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: vedantmgoyal9/winget-releaser@main
12 | with:
13 | identifier: pizzaboxer.Bloxstrap
14 | token: ${{ secrets.WINGET_TOKEN }}
15 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "wpfui"]
2 | path = wpfui
3 | url = https://github.com/bloxstraplabs/wpfui.git
4 |
--------------------------------------------------------------------------------
/Bloxstrap.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32819.101
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bloxstrap", "Bloxstrap\Bloxstrap.csproj", "{0D75146E-DA24-4B05-B6C9-250C8F81B0C7}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wpf.Ui", "wpfui\src\Wpf.Ui\Wpf.Ui.csproj", "{1ADC87D1-8963-4100-845A-18477824718E}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {0D75146E-DA24-4B05-B6C9-250C8F81B0C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {0D75146E-DA24-4B05-B6C9-250C8F81B0C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {0D75146E-DA24-4B05-B6C9-250C8F81B0C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {0D75146E-DA24-4B05-B6C9-250C8F81B0C7}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {1ADC87D1-8963-4100-845A-18477824718E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {1ADC87D1-8963-4100-845A-18477824718E}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {1ADC87D1-8963-4100-845A-18477824718E}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {1ADC87D1-8963-4100-845A-18477824718E}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | RESX_NeutralResourcesLanguage = en-GB
30 | SolutionGuid = {ED269E5D-8C72-49B4-A76F-51CF163511C1}
31 | EndGlobalSection
32 | EndGlobal
33 |
--------------------------------------------------------------------------------
/Bloxstrap/App.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | pack://application:,,,/Resources/Fonts/#Rubik Light
19 |
20 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Bloxstrap/AppData/IAppData.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.AppData
2 | {
3 | internal interface IAppData
4 | {
5 | string ProductName { get; }
6 |
7 | string BinaryType { get; }
8 |
9 | string RegistryName { get; }
10 |
11 | string ExecutableName { get; }
12 |
13 | string Directory { get; }
14 |
15 | string ExecutablePath { get; }
16 |
17 | AppState State { get; }
18 |
19 | IReadOnlyDictionary PackageDirectoryMap { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Bloxstrap/AppData/RobloxPlayerData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.AppData
8 | {
9 | public class RobloxPlayerData : CommonAppData, IAppData
10 | {
11 | public string ProductName => "Roblox";
12 |
13 | public string BinaryType => "WindowsPlayer";
14 |
15 | public string RegistryName => "RobloxPlayer";
16 |
17 | public override string ExecutableName => "RobloxPlayerBeta.exe";
18 |
19 | public override AppState State => App.RobloxState.Prop.Player;
20 |
21 | public override IReadOnlyDictionary PackageDirectoryMap { get; set; } = new Dictionary()
22 | {
23 | { "RobloxApp.zip", @"" }
24 | };
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Bloxstrap/AppData/RobloxStudioData.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.AppData
2 | {
3 | public class RobloxStudioData : CommonAppData, IAppData
4 | {
5 | public string ProductName => "Roblox Studio";
6 |
7 | public string BinaryType => "WindowsStudio64";
8 |
9 | public string RegistryName => "RobloxStudio";
10 |
11 | public override string ExecutableName => "RobloxStudioBeta.exe";
12 |
13 | public override AppState State => App.RobloxState.Prop.Studio;
14 |
15 | public override IReadOnlyDictionary PackageDirectoryMap { get; set; } = new Dictionary()
16 | {
17 | { "RobloxStudio.zip", @"" },
18 | { "LibrariesQt5.zip", @"" },
19 |
20 | { "content-studio_svg_textures.zip", @"content\studio_svg_textures\"},
21 | { "content-qt_translations.zip", @"content\qt_translations\" },
22 | { "content-api-docs.zip", @"content\api_docs\" },
23 |
24 | { "extracontent-scripts.zip", @"ExtraContent\scripts\" },
25 |
26 | { "BuiltInPlugins.zip", @"BuiltInPlugins\" },
27 | { "BuiltInStandalonePlugins.zip", @"BuiltInStandalonePlugins\" },
28 |
29 | { "ApplicationConfig.zip", @"ApplicationConfig\" },
30 | { "Plugins.zip", @"Plugins\" },
31 | { "Qml.zip", @"Qml\" },
32 | { "StudioFonts.zip", @"StudioFonts\" },
33 | { "RibbonConfig.zip", @"RibbonConfig\" }
34 | };
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Bloxstrap/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Bloxstrap.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Bloxstrap.ico
--------------------------------------------------------------------------------
/Bloxstrap/Enums/BootstrapperIcon.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum BootstrapperIcon
4 | {
5 | [EnumName(StaticName = "Bloxstrap")]
6 | IconBloxstrap,
7 | [EnumName(StaticName = "2008")]
8 | Icon2008,
9 | [EnumName(StaticName = "2011")]
10 | Icon2011,
11 | IconEarly2015,
12 | IconLate2015,
13 | [EnumName(StaticName = "2017")]
14 | Icon2017,
15 | [EnumName(StaticName = "2019")]
16 | Icon2019,
17 | [EnumName(StaticName = "2022")]
18 | Icon2022,
19 | [EnumName(FromTranslation = "Common.Custom")]
20 | IconCustom,
21 | [EnumName(FromTranslation = "Enums.BootstrapperStyle.ClassicFluentDialog")]
22 | IconBloxstrapClassic
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/BootstrapperStyle.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum BootstrapperStyle
4 | {
5 | VistaDialog,
6 | LegacyDialog2008,
7 | LegacyDialog2011,
8 | ProgressDialog,
9 | ClassicFluentDialog,
10 | ByfronDialog,
11 | [EnumName(StaticName = "Bloxstrap")]
12 | FluentDialog,
13 | FluentAeroDialog,
14 | CustomDialog
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/CursorType.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum CursorType
4 | {
5 | [EnumSort(Order = 1)]
6 | [EnumName(FromTranslation = "Common.Default")]
7 | Default,
8 |
9 | [EnumSort(Order = 3)]
10 | From2006,
11 |
12 | [EnumSort(Order = 2)]
13 | From2013
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/CustomThemeTemplate.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum CustomThemeTemplate
4 | {
5 | Blank,
6 | Simple
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/EmojiType.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum EmojiType
4 | {
5 | Default,
6 | Catmoji,
7 | Windows11,
8 | Windows10,
9 | Windows8
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/ErrorCode.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | // https://learn.microsoft.com/en-us/windows/win32/msi/error-codes
4 | // https://i-logic.com/serial/errorcodes.htm
5 | // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/705fb797-2175-4a90-b5a3-3918024b10b8
6 | // just the ones that we're interested in
7 |
8 | public enum ErrorCode
9 | {
10 | ERROR_SUCCESS = 0,
11 | ERROR_INVALID_FUNCTION = 1,
12 | ERROR_FILE_NOT_FOUND = 2,
13 |
14 | ERROR_CANCELLED = 1223,
15 | ERROR_INSTALL_USEREXIT = 1602,
16 | ERROR_INSTALL_FAILURE = 1603,
17 |
18 | CO_E_APPNOTFOUND = -2147221003
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/FlagPresets/InGameMenuVersion.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums.FlagPresets
2 | {
3 | public enum InGameMenuVersion
4 | {
5 | [EnumName(FromTranslation = "Common.Default")]
6 | Default,
7 | V1,
8 | V2,
9 | V4,
10 | V4Chrome
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/FlagPresets/LightingMode.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums.FlagPresets
2 | {
3 | public enum LightingMode
4 | {
5 | Default,
6 | Voxel,
7 | ShadowMap,
8 | Future
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/FlagPresets/MSAAMode.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums.FlagPresets
2 | {
3 | public enum MSAAMode
4 | {
5 | [EnumName(FromTranslation = "Common.Automatic")]
6 | Default,
7 | [EnumName(StaticName = "1x")]
8 | x1,
9 | [EnumName(StaticName = "2x")]
10 | x2,
11 | [EnumName(StaticName = "4x")]
12 | x4
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/FlagPresets/RenderingMode.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums.FlagPresets
2 | {
3 | public enum RenderingMode
4 | {
5 | [EnumName(FromTranslation = "Common.Automatic")]
6 | Default,
7 | D3D11,
8 | D3D10,
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/FlagPresets/TextureQuality.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums.FlagPresets
2 | {
3 | public enum TextureQuality
4 | {
5 | [EnumName(FromTranslation = "Common.Automatic")]
6 | Default,
7 | Level0,
8 | Level1,
9 | Level2,
10 | Level3
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/GenericTriState.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum GenericTriState
4 | {
5 | Successful,
6 | Failed,
7 | Unknown
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/LaunchMode.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum LaunchMode
4 | {
5 | None,
6 | ///
7 | /// Launch mode will be determined inside the bootstrapper. Only works if the VersionFlag is set.
8 | ///
9 | Unknown,
10 | Player,
11 | Studio,
12 | StudioAuth
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/NextAction.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum NextAction
4 | {
5 | Terminate,
6 | LaunchSettings,
7 | LaunchRoblox,
8 | LaunchRobloxStudio
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/ServerType.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum ServerType
4 | {
5 | Public,
6 | Private,
7 | Reserved
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/Theme.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | public enum Theme
4 | {
5 | [EnumName(FromTranslation = "Common.SystemDefault")]
6 | Default,
7 | Light,
8 | Dark
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/VersionComparison.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Enums
2 | {
3 | enum VersionComparison
4 | {
5 | LessThan = -1,
6 | Equal = 0,
7 | GreaterThan = 1
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Bloxstrap/Enums/WebEnvironment.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace Bloxstrap.Enums
4 | {
5 | [JsonConverter(typeof(JsonStringEnumConverter))]
6 | public enum WebEnvironment
7 | {
8 | [Description("prod")]
9 | Production,
10 |
11 | [Description("stage")]
12 | Staging,
13 |
14 | [Description("dev")]
15 | Dev,
16 |
17 | [Description("pizza")]
18 | DevPizza,
19 |
20 | [Description("matt")]
21 | DevMatt,
22 |
23 | [Description("local")]
24 | Local
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Bloxstrap/Exceptions/AssertionException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Exceptions
8 | {
9 | internal class AssertionException : Exception
10 | {
11 | public AssertionException(string message)
12 | : base($"{message}\n\nThis is very likely just an off-chance error. Please report this first, and then start {App.ProjectName} again.")
13 | {
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Bloxstrap/Exceptions/ChecksumFailedException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Exceptions
8 | {
9 | internal class ChecksumFailedException : Exception
10 | {
11 | public ChecksumFailedException(string message) : base(message)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Bloxstrap/Exceptions/CustomThemeException.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.Extensions;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Bloxstrap.Exceptions
9 | {
10 | internal class CustomThemeException : Exception
11 | {
12 | ///
13 | /// The exception message in English (for logging)
14 | ///
15 | public string EnglishMessage { get; } = null!;
16 |
17 | public CustomThemeException(string translationString)
18 | : base(Strings.ResourceManager.GetStringSafe(translationString))
19 | {
20 | EnglishMessage = Strings.ResourceManager.GetStringSafe(translationString, new CultureInfo("en-GB"));
21 | }
22 |
23 | public CustomThemeException(Exception innerException, string translationString)
24 | : base(Strings.ResourceManager.GetStringSafe(translationString), innerException)
25 | {
26 | EnglishMessage = Strings.ResourceManager.GetStringSafe(translationString, new CultureInfo("en-GB"));
27 | }
28 |
29 | public CustomThemeException(string translationString, params object?[] args)
30 | : base(string.Format(Strings.ResourceManager.GetStringSafe(translationString), args))
31 | {
32 | EnglishMessage = string.Format(Strings.ResourceManager.GetStringSafe(translationString, new CultureInfo("en-GB")), args);
33 | }
34 |
35 | public CustomThemeException(Exception innerException, string translationString, params object?[] args)
36 | : base(string.Format(Strings.ResourceManager.GetStringSafe(translationString), args), innerException)
37 | {
38 | EnglishMessage = string.Format(Strings.ResourceManager.GetStringSafe(translationString, new CultureInfo("en-GB")), args);
39 | }
40 |
41 | public override string ToString()
42 | {
43 | StringBuilder sb = new StringBuilder(GetType().ToString());
44 |
45 | if (!string.IsNullOrEmpty(Message))
46 | sb.Append($": {Message}");
47 |
48 | if (!string.IsNullOrEmpty(EnglishMessage) && Message != EnglishMessage)
49 | sb.Append($" ({EnglishMessage})");
50 |
51 | if (InnerException != null)
52 | sb.Append($"\r\n ---> {InnerException}\r\n ");
53 |
54 | if (StackTrace != null)
55 | sb.Append($"\r\n{StackTrace}");
56 |
57 | return sb.ToString();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Bloxstrap/Exceptions/InvalidChannelException.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Exceptions
2 | {
3 | public class InvalidChannelException : Exception
4 | {
5 | public HttpStatusCode? StatusCode;
6 |
7 | public InvalidChannelException(HttpStatusCode? statusCode) : base()
8 | => StatusCode = statusCode;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Exceptions/InvalidHTTPResponseException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Exceptions
8 | {
9 | internal class InvalidHTTPResponseException : Exception
10 | {
11 | public InvalidHTTPResponseException(string message) : base(message) { }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/BootstrapperStyleEx.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Extensions
2 | {
3 | static class BootstrapperStyleEx
4 | {
5 | public static IBootstrapperDialog GetNew(this BootstrapperStyle bootstrapperStyle) => Frontend.GetBootstrapperDialog(bootstrapperStyle);
6 |
7 | public static IReadOnlyCollection Selections => new BootstrapperStyle[]
8 | {
9 | BootstrapperStyle.FluentDialog,
10 | BootstrapperStyle.FluentAeroDialog,
11 | BootstrapperStyle.ClassicFluentDialog,
12 | BootstrapperStyle.ByfronDialog,
13 | BootstrapperStyle.ProgressDialog,
14 | BootstrapperStyle.LegacyDialog2011,
15 | BootstrapperStyle.LegacyDialog2008,
16 | BootstrapperStyle.VistaDialog,
17 | BootstrapperStyle.CustomDialog
18 | };
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/CustomThemeTemplateEx.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace Bloxstrap.Extensions
4 | {
5 | static class CustomThemeTemplateEx
6 | {
7 | const string EXAMPLES_URL = "https://github.com/bloxstraplabs/custom-bootstrapper-examples";
8 |
9 | public static string GetFileName(this CustomThemeTemplate template)
10 | {
11 | return $"CustomBootstrapperTemplate_{template}.xml";
12 | }
13 |
14 | public static string GetFileContents(this CustomThemeTemplate template)
15 | {
16 | string contents = Encoding.UTF8.GetString(Resource.Get(template.GetFileName()).Result);
17 |
18 | switch (template)
19 | {
20 | case CustomThemeTemplate.Blank:
21 | {
22 | string moreText = string.Format(Strings.CustomTheme_Templates_Blank_MoreExamples, EXAMPLES_URL);
23 | return contents.Replace("{0}", Strings.CustomTheme_Templates_Blank_UIElements).Replace("{1}", moreText);
24 | }
25 | case CustomThemeTemplate.Simple:
26 | {
27 | string moreText = string.Format(Strings.CustomTheme_Templates_Simple_MoreExamples, EXAMPLES_URL);
28 | return contents.Replace("{0}", moreText);
29 | }
30 | default:
31 | Debug.Assert(false);
32 | return contents;
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/DateTimeEx.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Extensions
2 | {
3 | static class DateTimeEx
4 | {
5 | public static string ToFriendlyString(this DateTime dateTime)
6 | {
7 | return dateTime.ToString("dddd, d MMMM yyyy 'at' h:mm:ss tt", CultureInfo.InvariantCulture);
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/EmojiTypeEx.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Extensions
2 | {
3 | static class EmojiTypeEx
4 | {
5 | public static IReadOnlyDictionary Filenames => new Dictionary
6 | {
7 | { EmojiType.Catmoji, "Catmoji.ttf" },
8 | { EmojiType.Windows11, "Win1122H2SegoeUIEmoji.ttf" },
9 | { EmojiType.Windows10, "Win10April2018SegoeUIEmoji.ttf" },
10 | { EmojiType.Windows8, "Win8.1SegoeUIEmoji.ttf" },
11 | };
12 |
13 | public static IReadOnlyDictionary Hashes => new Dictionary
14 | {
15 | { EmojiType.Catmoji, "98138f398a8cde897074dd2b8d53eca0" },
16 | { EmojiType.Windows11, "d50758427673578ddf6c9edcdbf367f5" },
17 | { EmojiType.Windows10, "d8a7eecbebf9dfdf622db8ccda63aff5" },
18 | { EmojiType.Windows8, "2b01c6caabbe95afc92aa63b9bf100f3" },
19 | };
20 |
21 | public static string GetHash(this EmojiType emojiType) => Hashes[emojiType];
22 |
23 | public static string GetUrl(this EmojiType emojiType)
24 | {
25 | if (emojiType == EmojiType.Default)
26 | return "";
27 |
28 | return $"https://github.com/bloxstraplabs/rbxcustom-fontemojis/releases/download/my-phone-is-78-percent/{Filenames[emojiType]}";
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/IconEx.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using System.Windows.Media.Imaging;
3 | using System.Windows.Media;
4 |
5 | namespace Bloxstrap.Extensions
6 | {
7 | public static class IconEx
8 | {
9 | public static Icon GetSized(this Icon icon, int width, int height) => new(icon, new Size(width, height));
10 |
11 | public static ImageSource GetImageSource(this Icon icon, bool handleException = true)
12 | {
13 | using MemoryStream stream = new();
14 | icon.Save(stream);
15 |
16 | if (handleException)
17 | {
18 | try
19 | {
20 | return BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
21 | }
22 | catch (Exception ex)
23 | {
24 | App.Logger.WriteException("IconEx::GetImageSource", ex);
25 | Frontend.ShowMessageBox(String.Format(Strings.Dialog_IconLoadFailed, ex.Message));
26 | return BootstrapperIcon.IconBloxstrap.GetIcon().GetImageSource(false);
27 | }
28 | }
29 | else
30 | {
31 | return BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/RegistryKeyEx.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 |
3 | namespace Bloxstrap.Extensions
4 | {
5 | public static class RegistryKeyEx
6 | {
7 | public static void SetValueSafe(this RegistryKey registryKey, string? name, object value)
8 | {
9 | try
10 | {
11 | App.Logger.WriteLine("RegistryKeyEx::SetValueSafe", $"Writing '{value}' to {registryKey}\\{name}");
12 | registryKey.SetValue(name, value);
13 | }
14 | catch (UnauthorizedAccessException)
15 | {
16 | Frontend.ShowMessageBox(Strings.Dialog_RegistryWriteError, System.Windows.MessageBoxImage.Error);
17 | App.Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
18 | }
19 | }
20 |
21 | public static void DeleteValueSafe(this RegistryKey registryKey, string name)
22 | {
23 | try
24 | {
25 | App.Logger.WriteLine("RegistryKeyEx::DeleteValueSafe", $"Deleting {registryKey}\\{name}");
26 | registryKey.DeleteValue(name);
27 | }
28 | catch (UnauthorizedAccessException)
29 | {
30 | Frontend.ShowMessageBox(Strings.Dialog_RegistryWriteError, System.Windows.MessageBoxImage.Error);
31 | App.Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/ResourceManagerEx.cs:
--------------------------------------------------------------------------------
1 | using System.Resources;
2 |
3 | namespace Bloxstrap.Extensions
4 | {
5 | static class ResourceManagerEx
6 | {
7 | ///
8 | /// Returns the value of the specified string resource.
9 | /// If the resource is not found, the resource name will be returned.
10 | ///
11 | public static string GetStringSafe(this ResourceManager manager, string name) => manager.GetStringSafe(name, null);
12 |
13 | ///
14 | /// Returns the value of the string resource localized for the specified culture.
15 | /// If the resource is not found, the resource name will be returned.
16 | ///
17 | public static string GetStringSafe(this ResourceManager manager, string name, CultureInfo? culture)
18 | {
19 | string? resourceValue = manager.GetString(name, culture);
20 |
21 | return resourceValue ?? name;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/ServerTypeEx.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Extensions
2 | {
3 | static class ServerTypeEx
4 | {
5 | public static string ToTranslatedString(this ServerType value) => value switch
6 | {
7 | ServerType.Public => Strings.Enums_ServerType_Public,
8 | ServerType.Private => Strings.Enums_ServerType_Private,
9 | ServerType.Reserved => Strings.Enums_ServerType_Reserved,
10 | _ => "?"
11 | };
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/TEnumEx.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Reflection;
3 |
4 | namespace Bloxstrap.Extensions
5 | {
6 | internal static class TEnumEx
7 | {
8 | public static string? GetDescription(this TEnum e)
9 | {
10 | string? enumName = e?.ToString();
11 | if (enumName == null)
12 | return null;
13 |
14 | FieldInfo? field = e?.GetType().GetField(enumName);
15 | if (field == null)
16 | return null;
17 |
18 | DescriptionAttribute? attribute = field.GetCustomAttribute();
19 | return attribute?.Description;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Bloxstrap/Extensions/ThemeEx.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 |
3 | namespace Bloxstrap.Extensions
4 | {
5 | public static class ThemeEx
6 | {
7 | public static Theme GetFinal(this Theme dialogTheme)
8 | {
9 | if (dialogTheme != Theme.Default)
10 | return dialogTheme;
11 |
12 | using var key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize");
13 |
14 | if (key?.GetValue("AppsUseLightTheme") is int value && value == 0)
15 | return Theme.Dark;
16 |
17 | return Theme.Light;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Bloxstrap/GlobalCache.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap
2 | {
3 | public static class GlobalCache
4 | {
5 | public static readonly Dictionary ServerLocation = new();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Bloxstrap/GlobalUsings.cs:
--------------------------------------------------------------------------------
1 | global using System;
2 | global using System.Collections.Generic;
3 | global using System.Diagnostics;
4 | global using System.Globalization;
5 | global using System.IO;
6 | global using System.Text;
7 | global using System.Text.Json;
8 | global using System.Text.Json.Serialization;
9 | global using System.Text.RegularExpressions;
10 | global using System.Linq;
11 | global using System.Net;
12 | global using System.Net.Http;
13 | global using System.Threading;
14 | global using System.Threading.Tasks;
15 |
16 | global using Bloxstrap.Enums;
17 | global using Bloxstrap.Exceptions;
18 | global using Bloxstrap.Extensions;
19 | global using Bloxstrap.Models;
20 | global using Bloxstrap.Models.APIs.Config;
21 | global using Bloxstrap.Models.APIs.GitHub;
22 | global using Bloxstrap.Models.APIs.Roblox;
23 | global using Bloxstrap.Models.Attributes;
24 | global using Bloxstrap.Models.BloxstrapRPC;
25 | global using Bloxstrap.Models.Entities;
26 | global using Bloxstrap.Models.Manifest;
27 | global using Bloxstrap.Models.Persistable;
28 | global using Bloxstrap.Models.SettingTasks;
29 | global using Bloxstrap.Models.SettingTasks.Base;
30 | global using Bloxstrap.Resources;
31 | global using Bloxstrap.UI;
32 | global using Bloxstrap.Utility;
--------------------------------------------------------------------------------
/Bloxstrap/HttpClientLoggingHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap
2 | {
3 | internal class HttpClientLoggingHandler : MessageProcessingHandler
4 | {
5 | public HttpClientLoggingHandler(HttpMessageHandler innerHandler)
6 | : base(innerHandler)
7 | {
8 | }
9 |
10 | protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
11 | {
12 | App.Logger.WriteLine("HttpClientLoggingHandler::ProcessRequest", $"{request.Method} {request.RequestUri}");
13 | return request;
14 | }
15 |
16 | protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
17 | {
18 | App.Logger.WriteLine("HttpClientLoggingHandler::ProcessResponse", $"{(int)response.StatusCode} {response.ReasonPhrase} {response.RequestMessage!.RequestUri}");
19 | return response;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Config/Supporter.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Config
2 | {
3 | public class Supporter
4 | {
5 | [JsonPropertyName("imageAsset")]
6 | public string ImageAsset { get; set; } = null!;
7 |
8 | [JsonPropertyName("name")]
9 | public string Name { get; set; } = null!;
10 |
11 | public string Image => $"https://raw.githubusercontent.com/bloxstraplabs/config/main/assets/{ImageAsset}";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Config/SupporterData.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Config
2 | {
3 | public class SupporterData
4 | {
5 | [JsonPropertyName("monthly")]
6 | public SupporterGroup Monthly { get; set; } = new();
7 |
8 | [JsonPropertyName("oneoff")]
9 | public SupporterGroup OneOff { get; set; } = new();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Config/SupporterGroup.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Config
2 | {
3 | public class SupporterGroup
4 | {
5 | [JsonPropertyName("columns")]
6 | public int Columns { get; set; } = 0;
7 |
8 | [JsonPropertyName("supporters")]
9 | public List Supporters { get; set; } = Enumerable.Empty().ToList();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/GitHub/GitHubReleaseAsset.cs:
--------------------------------------------------------------------------------
1 | public class GithubReleaseAsset
2 | {
3 | [JsonPropertyName("browser_download_url")]
4 | public string BrowserDownloadUrl { get; set; } = null!;
5 |
6 | [JsonPropertyName("name")]
7 | public string Name { get; set; } = null!;
8 | }
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/GitHub/GithubRelease.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.GitHub
2 | {
3 | public class GithubRelease
4 | {
5 | [JsonPropertyName("tag_name")]
6 | public string TagName { get; set; } = null!;
7 |
8 | [JsonPropertyName("name")]
9 | public string Name { get; set; } = null!;
10 |
11 | [JsonPropertyName("body")]
12 | public string Body { get; set; } = null!;
13 |
14 | [JsonPropertyName("created_at")]
15 | public string CreatedAt { get; set; } = null!;
16 |
17 | [JsonPropertyName("assets")]
18 | public List? Assets { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/IPInfoResponse.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs
2 | {
3 | public class IPInfoResponse
4 | {
5 | [JsonPropertyName("city")]
6 | public string City { get; set; } = null!;
7 |
8 | [JsonPropertyName("country")]
9 | public string Country { get; set; } = null!;
10 |
11 | [JsonPropertyName("region")]
12 | public string Region { get; set; } = null!;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/ApiArrayResponse.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Roblox
2 | {
3 | ///
4 | /// Roblox.Web.WebAPI.Models.ApiArrayResponse
5 | ///
6 | public class ApiArrayResponse
7 | {
8 | [JsonPropertyName("data")]
9 | public IEnumerable Data { get; set; } = null!;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/ClientFlagSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Roblox
2 | {
3 | public class ClientFlagSettings
4 | {
5 | [JsonPropertyName("applicationSettings")]
6 | public Dictionary? ApplicationSettings { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/ClientVersion.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Roblox
2 | {
3 | public class ClientVersion
4 | {
5 | [JsonPropertyName("version")]
6 | public string Version { get; set; } = null!;
7 |
8 | [JsonPropertyName("clientVersionUpload")]
9 | public string VersionGuid { get; set; } = null!;
10 |
11 | [JsonPropertyName("bootstrapperVersion")]
12 | public string BootstrapperVersion { get; set; } = null!;
13 |
14 | public DateTime? Timestamp { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/GameCreator.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Roblox
2 | {
3 | ///
4 | /// Roblox.Games.Api.Models.Response.GameCreator
5 | /// Response model for getting the game creator
6 | ///
7 | public class GameCreator
8 | {
9 | ///
10 | /// The game creator id
11 | ///
12 | [JsonPropertyName("id")]
13 | public long Id { get; set; }
14 |
15 | ///
16 | /// The game creator name
17 | ///
18 | [JsonPropertyName("name")]
19 | public string Name { get; set; } = null!;
20 |
21 | ///
22 | /// The game creator type
23 | ///
24 | [JsonPropertyName("type")]
25 | public string Type { get; set; } = null!;
26 |
27 | ///
28 | /// The game creator account is Luobu Real Name Verified
29 | ///
30 | [JsonPropertyName("isRNVAccount")]
31 | public bool IsRNVAccount { get; set; }
32 |
33 | ///
34 | /// Builder verified badge status.
35 | ///
36 | [JsonPropertyName("hasVerifiedBadge")]
37 | public bool HasVerifiedBadge { get; set; }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/GetUserResponse.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.RobloxApi
2 | {
3 | ///
4 | /// Roblox.Users.Api.GetUserResponse
5 | ///
6 | public class GetUserResponse
7 | {
8 | ///
9 | /// The user description.
10 | ///
11 | [JsonPropertyName("description")]
12 | public string Description { get; set; } = null!;
13 |
14 | ///
15 | /// When the user signed up.
16 | ///
17 | [JsonPropertyName("created")]
18 | public DateTime Created { get; set; }
19 |
20 | ///
21 | /// Whether the user is banned
22 | ///
23 | [JsonPropertyName("isBanned")]
24 | public bool IsBanned { get; set; }
25 |
26 | ///
27 | /// Unused, legacy attribute… rely on its existence.
28 | ///
29 | [JsonPropertyName("externalAppDisplayName")]
30 | public string ExternalAppDisplayName { get; set; } = null!;
31 |
32 | ///
33 | /// The user's verified badge status.
34 | ///
35 | [JsonPropertyName("hasVerifiedBadge")]
36 | public bool HasVerifiedBadge { get; set; }
37 |
38 | ///
39 | /// The user Id.
40 | ///
41 | [JsonPropertyName("id")]
42 | public long Id { get; set; }
43 |
44 | ///
45 | /// The user name.
46 | ///
47 | [JsonPropertyName("name")]
48 | public string Name { get; set; } = null!;
49 |
50 | ///
51 | /// The user DisplayName.
52 | ///
53 | [JsonPropertyName("displayName")]
54 | public string DisplayName { get; set; } = null!;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/ThumbnailBatchResponse.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Roblox
2 | {
3 | internal class ThumbnailBatchResponse
4 | {
5 | [JsonPropertyName("data")]
6 | public ThumbnailResponse[] Data { get; set; } = Array.Empty();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/ThumbnailRequest.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Roblox
2 | {
3 | internal class ThumbnailRequest
4 | {
5 | [JsonPropertyName("requestId")]
6 | public string? RequestId { get; set; }
7 |
8 | [JsonPropertyName("targetId")]
9 | public ulong TargetId { get; set; }
10 |
11 | ///
12 | /// TODO: make this an enum
13 | /// List of valid types can be found at https://thumbnails.roblox.com//docs/index.html
14 | ///
15 | [JsonPropertyName("type")]
16 | public string Type { get; set; } = "Avatar";
17 |
18 | ///
19 | /// List of valid sizes can be found at https://thumbnails.roblox.com//docs/index.html
20 | ///
21 | [JsonPropertyName("size")]
22 | public string Size { get; set; } = "30x30";
23 |
24 | ///
25 | /// TODO: make this an enum
26 | /// List of valid types can be found at https://thumbnails.roblox.com//docs/index.html
27 | ///
28 | [JsonPropertyName("format")]
29 | public string Format { get; set; } = "Png";
30 |
31 | [JsonPropertyName("isCircular")]
32 | public bool IsCircular { get; set; } = true;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/ThumbnailResponse.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Roblox
2 | {
3 | ///
4 | /// Roblox.Web.Responses.Thumbnails.ThumbnailResponse
5 | ///
6 | public class ThumbnailResponse
7 | {
8 | [JsonPropertyName("requestId")]
9 | public string RequestId { get; set; } = null!;
10 |
11 | [JsonPropertyName("errorCode")]
12 | public int ErrorCode { get; set; } = 0;
13 |
14 | [JsonPropertyName("errorMessage")]
15 | public string? ErrorMessage { get; set; } = null;
16 |
17 | [JsonPropertyName("targetId")]
18 | public long TargetId { get; set; }
19 |
20 | ///
21 | /// Valid states:
22 | /// - Error
23 | /// - Completed
24 | /// - InReview
25 | /// - Pending
26 | /// - Blocked
27 | /// - TemporarilyUnavailable
28 | ///
29 | [JsonPropertyName("state")]
30 | public string State { get; set; } = null!;
31 |
32 | [JsonPropertyName("imageUrl")]
33 | public string? ImageUrl { get; set; } = null!;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/APIs/Roblox/UniverseIdResponse.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.APIs.Roblox
2 | {
3 | // lmao its just one property
4 | public class UniverseIdResponse
5 | {
6 | [JsonPropertyName("universeId")]
7 | public long UniverseId { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Attributes/BuildMetadataAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.Attributes
2 | {
3 | [AttributeUsage(AttributeTargets.Assembly)]
4 | public class BuildMetadataAttribute : Attribute
5 | {
6 | public DateTime Timestamp { get; set; }
7 | public string Machine { get; set; }
8 | public string CommitHash { get; set; }
9 | public string CommitRef { get; set; }
10 |
11 | public BuildMetadataAttribute(string timestamp, string machine, string commitHash, string commitRef)
12 | {
13 | Timestamp = DateTime.Parse(timestamp).ToLocalTime();
14 | Machine = machine;
15 | CommitHash = commitHash;
16 | CommitRef = commitRef;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Attributes/EnumNameAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Models.Attributes
8 | {
9 | class EnumNameAttribute : Attribute
10 | {
11 | public string? StaticName { get; set; }
12 | public string? FromTranslation { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Attributes/EnumSortAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Models.Attributes
8 | {
9 | class EnumSortAttribute : Attribute
10 | {
11 | public int Order { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/BloxstrapRPC/Message.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.BloxstrapRPC;
2 |
3 | public class Message
4 | {
5 | [JsonPropertyName("command")]
6 | public string Command { get; set; } = null!;
7 |
8 | [JsonPropertyName("data")]
9 | public JsonElement Data { get; set; }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/BloxstrapRPC/RichPresence.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.BloxstrapRPC
2 | {
3 | class RichPresence
4 | {
5 | [JsonPropertyName("details")]
6 | public string? Details { get; set; }
7 |
8 | [JsonPropertyName("state")]
9 | public string? State { get; set; }
10 |
11 | [JsonPropertyName("timeStart")]
12 | public ulong? TimestampStart { get; set; }
13 |
14 | [JsonPropertyName("timeEnd")]
15 | public ulong? TimestampEnd { get; set; }
16 |
17 | [JsonPropertyName("smallImage")]
18 | public RichPresenceImage? SmallImage { get; set; }
19 |
20 | [JsonPropertyName("largeImage")]
21 | public RichPresenceImage? LargeImage { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/BloxstrapRPC/RichPresenceImage.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.BloxstrapRPC
2 | {
3 | class RichPresenceImage
4 | {
5 | [JsonPropertyName("assetId")]
6 | public ulong? AssetId { get; set; }
7 |
8 | [JsonPropertyName("hoverText")]
9 | public string? HoverText { get; set; }
10 |
11 | [JsonPropertyName("clear")]
12 | public bool Clear { get; set; } = false;
13 |
14 | [JsonPropertyName("reset")]
15 | public bool Reset { get; set; } = false;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/BootstrapperIconEntry.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Media;
2 |
3 | namespace Bloxstrap.Models
4 | {
5 | public class BootstrapperIconEntry
6 | {
7 | public BootstrapperIcon IconType { get; set; }
8 | public ImageSource ImageSource => IconType.GetIcon().GetImageSource();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/CustomIntegration.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models
2 | {
3 | public class CustomIntegration
4 | {
5 | public string Name { get; set; } = "";
6 | public string Location { get; set; } = "";
7 | public string LaunchArgs { get; set; } = "";
8 | public bool AutoClose { get; set; } = true;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/DeployInfo.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models
2 | {
3 | public class DeployInfo
4 | {
5 | public string Timestamp { get; set; } = null!;
6 | public string Version { get; set; } = null!;
7 | public string VersionGuid { get; set; } = null!;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Entities/ModPresetFileData.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 | using System.Windows.Markup;
3 |
4 | namespace Bloxstrap.Models.Entities
5 | {
6 | public class ModPresetFileData
7 | {
8 | public string FilePath { get; private set; }
9 |
10 | public string FullFilePath => Path.Combine(Paths.Modifications, FilePath);
11 |
12 | public FileStream FileStream => File.OpenRead(FullFilePath);
13 |
14 | public string ResourceIdentifier { get; private set; }
15 |
16 | public Stream ResourceStream => Resource.GetStream(ResourceIdentifier);
17 |
18 | public byte[] ResourceHash { get; private set; }
19 |
20 | public ModPresetFileData(string contentPath, string resource)
21 | {
22 | FilePath = contentPath;
23 | ResourceIdentifier = resource;
24 |
25 | using var stream = ResourceStream;
26 | ResourceHash = App.MD5Provider.ComputeHash(stream);
27 | }
28 |
29 | public bool HashMatches()
30 | {
31 | if (!File.Exists(FullFilePath))
32 | return false;
33 |
34 | using var fileStream = FileStream;
35 | var fileHash = App.MD5Provider.ComputeHash(fileStream);
36 |
37 | return fileHash.SequenceEqual(ResourceHash);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Entities/UniverseDetails.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.Entities
2 | {
3 | ///
4 | /// Explicit loading. Load from cache before and after a fetch.
5 | ///
6 | public class UniverseDetails
7 | {
8 | private static List _cache { get; set; } = new();
9 |
10 | public GameDetailResponse Data { get; set; } = null!;
11 |
12 | ///
13 | /// Returns data for a 128x128 icon
14 | ///
15 | public ThumbnailResponse Thumbnail { get; set; } = null!;
16 |
17 | public static UniverseDetails? LoadFromCache(long id)
18 | {
19 | var cacheQuery = _cache.Where(x => x.Data?.Id == id);
20 |
21 | if (cacheQuery.Any())
22 | return cacheQuery.First();
23 |
24 | return null;
25 | }
26 |
27 | public static Task FetchSingle(long id) => FetchBulk(id.ToString());
28 |
29 | public static async Task FetchBulk(string ids)
30 | {
31 | var gameDetailResponse = await Http.GetJson>($"https://games.roblox.com/v1/games?universeIds={ids}");
32 |
33 | if (!gameDetailResponse.Data.Any())
34 | throw new InvalidHTTPResponseException("Roblox API for Game Details returned invalid data");
35 |
36 | var universeThumbnailResponse = await Http.GetJson>($"https://thumbnails.roblox.com/v1/games/icons?universeIds={ids}&returnPolicy=PlaceHolder&size=128x128&format=Png&isCircular=false");
37 |
38 | if (!universeThumbnailResponse.Data.Any())
39 | throw new InvalidHTTPResponseException("Roblox API for Game Thumbnails returned invalid data");
40 |
41 | foreach (string strId in ids.Split(','))
42 | {
43 | long id = long.Parse(strId);
44 |
45 | _cache.Add(new UniverseDetails
46 | {
47 | Data = gameDetailResponse.Data.Where(x => x.Id == id).First(),
48 | Thumbnail = universeThumbnailResponse.Data.Where(x => x.TargetId == id).First(),
49 | });
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Entities/UserDetails.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.Models.RobloxApi;
2 |
3 | namespace Bloxstrap.Models.Entities
4 | {
5 | public class UserDetails
6 | {
7 | private static List _cache { get; set; } = new();
8 |
9 | public GetUserResponse Data { get; set; } = null!;
10 |
11 | public ThumbnailResponse Thumbnail { get; set; } = null!;
12 |
13 | public static async Task Fetch(long id)
14 | {
15 | var cacheQuery = _cache.Where(x => x.Data?.Id == id);
16 |
17 | if (cacheQuery.Any())
18 | return cacheQuery.First();
19 |
20 | var userResponse = await Http.GetJson($"https://users.roblox.com/v1/users/{id}");
21 |
22 | if (userResponse is null)
23 | throw new InvalidHTTPResponseException("Roblox API for User Details returned invalid data");
24 |
25 | // we can remove '-headshot' from the url if we want a full avatar picture
26 | var thumbnailResponse = await Http.GetJson>($"https://thumbnails.roblox.com/v1/users/avatar-headshot?userIds={id}&size=180x180&format=Png&isCircular=false");
27 |
28 | if (thumbnailResponse is null || !thumbnailResponse.Data.Any())
29 | throw new InvalidHTTPResponseException("Roblox API for Thumbnails returned invalid data");
30 |
31 | var details = new UserDetails
32 | {
33 | Data = userResponse,
34 | Thumbnail = thumbnailResponse.Data.First()
35 | };
36 |
37 | _cache.Add(details);
38 |
39 | return details;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/FastFlag.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models
2 | {
3 | public class FastFlag
4 | {
5 | // public bool Enabled { get; set; }
6 | public string Name { get; set; } = null!;
7 | public string Value { get; set; } = null!;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/FontFace.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models
2 | {
3 | public class FontFace
4 | {
5 | [JsonPropertyName("name")]
6 | public string Name { get; set; } = null!;
7 |
8 | [JsonPropertyName("weight")]
9 | public int Weight { get; set; }
10 |
11 | [JsonPropertyName("style")]
12 | public string Style { get; set; } = null!;
13 |
14 | [JsonPropertyName("assetId")]
15 | public string AssetId { get; set; } = null!;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/FontFamily.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models
2 | {
3 | public class FontFamily
4 | {
5 | [JsonPropertyName("name")]
6 | public string Name { get; set; } = null!;
7 |
8 | [JsonPropertyName("faces")]
9 | public IEnumerable Faces { get; set; } = null!;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/LaunchFlag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Models
8 | {
9 | public class LaunchFlag
10 | {
11 | public string Identifiers { get; private set; }
12 |
13 | public bool Active = false;
14 |
15 | public string? Data;
16 |
17 | public LaunchFlag(string identifiers)
18 | {
19 | Identifiers = identifiers;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Manifest/FileManifest.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.RobloxInterfaces;
2 |
3 | namespace Bloxstrap.Models.Manifest
4 | {
5 | public class FileManifest : List
6 | {
7 | private FileManifest(string data)
8 | {
9 | using StringReader reader = new StringReader(data);
10 |
11 | while (true)
12 | {
13 | string? fileName = reader.ReadLine();
14 | string? signature = reader.ReadLine();
15 |
16 | if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(signature))
17 | break;
18 |
19 | Add(new ManifestFile
20 | {
21 | Name = fileName,
22 | Signature = signature
23 | });
24 | }
25 | }
26 |
27 | public static async Task Get(string versionGuid)
28 | {
29 | string pkgManifestUrl = Deployment.GetLocation($"/{versionGuid}-rbxManifest.txt");
30 | var pkgManifestData = await App.HttpClient.GetStringAsync(pkgManifestUrl);
31 |
32 | return new FileManifest(pkgManifestData);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Manifest/ManifestFile.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.Manifest
2 | {
3 | public class ManifestFile
4 | {
5 | public string Name { get; set; } = "";
6 | public string Signature { get; set; } = "";
7 |
8 | public override string ToString()
9 | {
10 | return $"[{Signature}] {Name}";
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Manifest/Package.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Roblox Studio Mod Manager (ProjectSrc/Utility/Package.cs)
3 | * MIT License
4 | * Copyright (c) 2015-present MaximumADHD
5 | */
6 |
7 | namespace Bloxstrap.Models.Manifest
8 | {
9 | public class Package
10 | {
11 | public string Name { get; set; } = "";
12 |
13 | public string Signature { get; set; } = "";
14 |
15 | public int PackedSize { get; set; }
16 |
17 | public int Size { get; set; }
18 |
19 | public string DownloadPath => Path.Combine(Paths.Downloads, Signature);
20 |
21 | public override string ToString()
22 | {
23 | return $"[{Signature}] {Name}";
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Manifest/PackageManifest.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Roblox Studio Mod Manager (ProjectSrc/Utility/PackageManifest.cs)
3 | * MIT License
4 | * Copyright (c) 2015-present MaximumADHD
5 | */
6 |
7 | namespace Bloxstrap.Models.Manifest
8 | {
9 | public class PackageManifest : List
10 | {
11 | public PackageManifest(string data)
12 | {
13 | using var reader = new StringReader(data);
14 | string? version = reader.ReadLine();
15 |
16 | if (version != "v0")
17 | throw new NotSupportedException($"Unexpected package manifest version: {version} (expected v0!)");
18 |
19 | while (true)
20 | {
21 | string? fileName = reader.ReadLine();
22 | string? signature = reader.ReadLine();
23 |
24 | string? rawPackedSize = reader.ReadLine();
25 | string? rawSize = reader.ReadLine();
26 |
27 | if (string.IsNullOrEmpty(fileName) ||
28 | string.IsNullOrEmpty(signature) ||
29 | string.IsNullOrEmpty(rawPackedSize) ||
30 | string.IsNullOrEmpty(rawSize))
31 | break;
32 |
33 | // ignore launcher
34 | if (fileName == "RobloxPlayerLauncher.exe")
35 | break;
36 |
37 | int packedSize = int.Parse(rawPackedSize);
38 | int size = int.Parse(rawSize);
39 |
40 | Add(new Package
41 | {
42 | Name = fileName,
43 | Signature = signature,
44 | PackedSize = packedSize,
45 | Size = size
46 | });
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Persistable/AppState.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.Persistable
2 | {
3 | public class AppState
4 | {
5 | public string VersionGuid { get; set; } = string.Empty;
6 |
7 | public Dictionary PackageHashes { get; set; } = new();
8 |
9 | public int Size { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Persistable/RobloxState.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.Persistable
2 | {
3 | public class RobloxState
4 | {
5 | public AppState Player { get; set; } = new();
6 |
7 | public AppState Studio { get; set; } = new();
8 |
9 | public List ModManifest { get; set; } = new();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Persistable/Settings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 |
3 | namespace Bloxstrap.Models.Persistable
4 | {
5 | public class Settings
6 | {
7 | // bloxstrap configuration
8 | public BootstrapperStyle BootstrapperStyle { get; set; } = BootstrapperStyle.FluentDialog;
9 | public BootstrapperIcon BootstrapperIcon { get; set; } = BootstrapperIcon.IconBloxstrap;
10 | public string BootstrapperTitle { get; set; } = App.ProjectName;
11 | public string BootstrapperIconCustomLocation { get; set; } = "";
12 | public Theme Theme { get; set; } = Theme.Default;
13 | [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
14 | public bool DeveloperMode { get; set; } = false;
15 | public bool CheckForUpdates { get; set; } = true;
16 | public bool MultiInstanceLaunching { get; set; } = false;
17 | public bool ConfirmLaunches { get; set; } = false;
18 | public string Locale { get; set; } = "nil";
19 | public bool ForceRobloxLanguage { get; set; } = false;
20 | public bool UseFastFlagManager { get; set; } = true;
21 | public bool WPFSoftwareRender { get; set; } = false;
22 | public bool EnableAnalytics { get; set; } = true;
23 | public bool BackgroundUpdatesEnabled { get; set; } = false;
24 | public bool DebugDisableVersionPackageCleanup { get; set; } = false;
25 | public string? SelectedCustomTheme { get; set; } = null;
26 | public WebEnvironment WebEnvironment { get; set; } = WebEnvironment.Production;
27 |
28 | // integration configuration
29 | public bool EnableActivityTracking { get; set; } = true;
30 | public bool UseDiscordRichPresence { get; set; } = true;
31 | public bool HideRPCButtons { get; set; } = true;
32 | public bool ShowAccountOnRichPresence { get; set; } = false;
33 | public bool ShowServerDetails { get; set; } = false;
34 | public ObservableCollection CustomIntegrations { get; set; } = new();
35 |
36 | // mod preset configuration
37 | public bool UseDisableAppPatch { get; set; } = false;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Persistable/State.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.Persistable
2 | {
3 | public class State
4 | {
5 | public bool ShowFFlagEditorWarning { get; set; } = true;
6 |
7 | public bool PromptWebView2Install { get; set; } = true;
8 |
9 | public bool ForceReinstall { get; set; } = false;
10 |
11 | public WindowState SettingsWindow { get; set; } = new();
12 |
13 | #region Deprecated properties
14 | ///
15 | /// Deprecated, use App.RobloxState.Player
16 | ///
17 | public AppState? Player { private get; set; }
18 | public AppState? GetDeprecatedPlayer() => Player;
19 |
20 | ///
21 | /// Deprecated, use App.RobloxState.Studio
22 | ///
23 | public AppState? Studio { private get; set; }
24 | public AppState? GetDeprecatedStudio() => Studio;
25 |
26 | ///
27 | /// Deprecated, use App.RobloxState.ModManifest
28 | ///
29 | public List? ModManifest { private get; set; }
30 | public List? GetDeprecatedModManifest() => ModManifest;
31 | #endregion
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/Persistable/WindowState.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.Persistable
2 | {
3 | public class WindowState
4 | {
5 | public double Width { get; set; }
6 |
7 | public double Height { get; set; }
8 |
9 | public double Left { get; set; }
10 |
11 | public double Top { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/Base/BaseTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Models.SettingTasks.Base
8 | {
9 | public abstract class BaseTask
10 | {
11 | public string Name { get; private set; }
12 |
13 | public abstract bool Changed { get; }
14 |
15 | public BaseTask(string prefix, string name) : this($"{prefix}.{name}") { }
16 |
17 | public BaseTask(string name) => Name = name;
18 |
19 | public override string ToString() => Name;
20 |
21 | public abstract void Execute();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/Base/BoolBaseTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Models.SettingTasks.Base
8 | {
9 | public abstract class BoolBaseTask : BaseTask
10 | {
11 | private bool _originalState;
12 |
13 | private bool _newState;
14 |
15 | public virtual bool OriginalState
16 | {
17 | get => _originalState;
18 |
19 | set
20 | {
21 | _originalState = value;
22 | _newState = value;
23 | }
24 | }
25 |
26 | public virtual bool NewState
27 | {
28 | get => _newState;
29 |
30 | set
31 | {
32 | _newState = value;
33 |
34 | if (Changed)
35 | App.PendingSettingTasks[Name] = this;
36 | else
37 | App.PendingSettingTasks.Remove(Name);
38 | }
39 | }
40 |
41 | public override bool Changed => _newState != OriginalState;
42 |
43 | public BoolBaseTask(string prefix, string name) : base(prefix, name) { }
44 |
45 | public BoolBaseTask(string name) : base(name) { }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/Base/EnumBaseTask.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.SettingTasks.Base
2 | {
3 | public abstract class EnumBaseTask : BaseTask where T : struct, Enum
4 | {
5 | private T _originalState = default!;
6 |
7 | private T _newState = default!;
8 |
9 | public virtual T OriginalState
10 | {
11 | get => _originalState;
12 |
13 | set
14 | {
15 | _originalState = value;
16 | _newState = value;
17 | }
18 | }
19 |
20 | public virtual T NewState
21 | {
22 | get => _newState;
23 |
24 | set
25 | {
26 | _newState = value;
27 |
28 | if (Changed)
29 | App.PendingSettingTasks[Name] = this;
30 | else
31 | App.PendingSettingTasks.Remove(Name);
32 | }
33 | }
34 |
35 | public override bool Changed => !_newState.Equals(OriginalState);
36 |
37 | public IEnumerable Selections { get; private set; }
38 | = Enum.GetValues(typeof(T)).Cast().OrderBy(x =>
39 | {
40 | var attributes = x.GetType().GetMember(x.ToString())[0].GetCustomAttributes(typeof(EnumSortAttribute), false);
41 |
42 | if (attributes.Length > 0)
43 | {
44 | var attribute = (EnumSortAttribute)attributes[0];
45 | return attribute.Order;
46 | }
47 |
48 | return 0;
49 | });
50 |
51 | public EnumBaseTask(string prefix, string name) : base(prefix, name) { }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/Base/StringBaseTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Models.SettingTasks.Base
8 | {
9 | public abstract class StringBaseTask : BaseTask
10 | {
11 | private string _originalState = "";
12 |
13 | private string _newState = "";
14 |
15 | public virtual string OriginalState
16 | {
17 | get => _originalState;
18 |
19 | set
20 | {
21 | _originalState = value;
22 | _newState = value;
23 | }
24 | }
25 |
26 | public virtual string NewState
27 | {
28 | get => _newState;
29 |
30 | set
31 | {
32 | _newState = value;
33 |
34 | if (Changed)
35 | App.PendingSettingTasks[Name] = this;
36 | else
37 | App.PendingSettingTasks.Remove(Name);
38 | }
39 | }
40 |
41 | public override bool Changed => _newState != OriginalState;
42 |
43 | public StringBaseTask(string prefix, string name) : base(prefix, name) { }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/EmojiModPresetTask.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | using Bloxstrap.Models.SettingTasks.Base;
4 |
5 | namespace Bloxstrap.Models.SettingTasks
6 | {
7 | public class EmojiModPresetTask : EnumBaseTask
8 | {
9 | private string _filePath => Path.Combine(Paths.Modifications, @"content\fonts\TwemojiMozilla.ttf");
10 |
11 | private IEnumerable>? QueryCurrentValue()
12 | {
13 | if (!File.Exists(_filePath))
14 | return null;
15 |
16 | using var fileStream = File.OpenRead(_filePath);
17 | string hash = MD5Hash.Stringify(App.MD5Provider.ComputeHash(fileStream));
18 |
19 | return EmojiTypeEx.Hashes.Where(x => x.Value == hash);
20 | }
21 |
22 | public EmojiModPresetTask() : base("ModPreset", "EmojiFont")
23 | {
24 | var query = QueryCurrentValue();
25 |
26 | if (query is not null)
27 | OriginalState = query.FirstOrDefault().Key;
28 | }
29 |
30 | public override async void Execute()
31 | {
32 | const string LOG_IDENT = "EmojiModPresetTask::Execute";
33 |
34 | var query = QueryCurrentValue();
35 |
36 | if (NewState != EmojiType.Default && (query is null || query.FirstOrDefault().Key != NewState))
37 | {
38 | try
39 | {
40 | var response = await App.HttpClient.GetAsync(NewState.GetUrl());
41 |
42 | response.EnsureSuccessStatusCode();
43 |
44 | Directory.CreateDirectory(Path.GetDirectoryName(_filePath)!);
45 |
46 | await using var fileStream = new FileStream(_filePath, FileMode.Create);
47 | await response.Content.CopyToAsync(fileStream);
48 |
49 | OriginalState = NewState;
50 | }
51 | catch (Exception ex)
52 | {
53 | App.Logger.WriteException(LOG_IDENT, ex);
54 |
55 | Frontend.ShowConnectivityDialog(
56 | String.Format(Strings.Dialog_Connectivity_UnableToConnect, "GitHub"),
57 | $"{Strings.Menu_Mods_Presets_EmojiType_Error}\n\n{Strings.Dialog_Connectivity_TryAgainLater}",
58 | MessageBoxImage.Warning,
59 | ex
60 | );
61 | }
62 | }
63 | else if (query is not null && query.Any())
64 | {
65 | Filesystem.AssertReadOnly(_filePath);
66 | File.Delete(_filePath);
67 |
68 | OriginalState = NewState;
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/EnumModPresetTask.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.Models.Entities;
2 | using Bloxstrap.Models.SettingTasks.Base;
3 |
4 | namespace Bloxstrap.Models.SettingTasks
5 | {
6 | public class EnumModPresetTask : EnumBaseTask where T : struct, Enum
7 | {
8 | private readonly Dictionary> _fileDataMap = new();
9 |
10 | private readonly Dictionary> _map;
11 |
12 | public EnumModPresetTask(string name, Dictionary> map) : base("ModPreset", name)
13 | {
14 | _map = map;
15 |
16 | foreach (var enumPair in _map)
17 | {
18 | var dataMap = new Dictionary();
19 |
20 | foreach (var resourcePair in enumPair.Value)
21 | {
22 | var data = new ModPresetFileData(resourcePair.Key, resourcePair.Value);
23 |
24 | if (data.HashMatches() && OriginalState.Equals(default(T)))
25 | OriginalState = enumPair.Key;
26 |
27 | dataMap[resourcePair.Key] = data;
28 | }
29 |
30 | _fileDataMap[enumPair.Key] = dataMap;
31 | }
32 | }
33 |
34 | public override void Execute()
35 | {
36 | if (!NewState.Equals(default(T)))
37 | {
38 | var resourceMap = _fileDataMap[NewState];
39 |
40 | foreach (var resourcePair in resourceMap)
41 | {
42 | var data = resourcePair.Value;
43 |
44 | if (!data.HashMatches())
45 | {
46 | Directory.CreateDirectory(Path.GetDirectoryName(data.FullFilePath)!);
47 |
48 | using var resourceStream = data.ResourceStream;
49 | using var memoryStream = new MemoryStream();
50 | data.ResourceStream.CopyTo(memoryStream);
51 |
52 | Filesystem.AssertReadOnly(data.FullFilePath);
53 | File.WriteAllBytes(data.FullFilePath, memoryStream.ToArray());
54 | }
55 | }
56 | }
57 | else
58 | {
59 | foreach (var dataPair in _fileDataMap.First().Value)
60 | {
61 | Filesystem.AssertReadOnly(dataPair.Value.FullFilePath);
62 | File.Delete(dataPair.Value.FullFilePath);
63 | }
64 | }
65 |
66 | OriginalState = NewState;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/ExtractIconsTask.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace Bloxstrap.Models.SettingTasks
4 | {
5 | public class ExtractIconsTask : BoolBaseTask
6 | {
7 | private string _path => Path.Combine(Paths.Base, Strings.Paths_Icons);
8 |
9 | public ExtractIconsTask() : base("ExtractIcons")
10 | {
11 | OriginalState = Directory.Exists(_path);
12 | }
13 |
14 | public override void Execute()
15 | {
16 | if (NewState)
17 | {
18 | Directory.CreateDirectory(_path);
19 |
20 | var assembly = Assembly.GetExecutingAssembly();
21 | var resourceNames = assembly.GetManifestResourceNames().Where(x => x.EndsWith(".ico"));
22 |
23 | foreach (string name in resourceNames)
24 | {
25 | string path = Path.Combine(_path, name.Replace("Bloxstrap.Resources.", ""));
26 | var stream = assembly.GetManifestResourceStream(name)!;
27 |
28 | using var memoryStream = new MemoryStream();
29 | stream.CopyTo(memoryStream);
30 |
31 | Filesystem.AssertReadOnly(path);
32 | File.WriteAllBytes(path, memoryStream.ToArray());
33 | }
34 | }
35 | else if (Directory.Exists(_path))
36 | {
37 | Directory.Delete(_path, true);
38 | }
39 |
40 | OriginalState = NewState;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/FontModPresetTask.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.Models.SettingTasks.Base;
2 |
3 | namespace Bloxstrap.Models.SettingTasks
4 | {
5 | public class FontModPresetTask : StringBaseTask
6 | {
7 | public string? GetFileHash()
8 | {
9 | if (!File.Exists(Paths.CustomFont))
10 | return null;
11 |
12 | using var fileStream = File.OpenRead(Paths.CustomFont);
13 | return MD5Hash.Stringify(App.MD5Provider.ComputeHash(fileStream));
14 | }
15 |
16 | public FontModPresetTask() : base("ModPreset", "TextFont")
17 | {
18 | if (File.Exists(Paths.CustomFont))
19 | OriginalState = Paths.CustomFont;
20 | }
21 |
22 | public override void Execute()
23 | {
24 | if (!String.IsNullOrEmpty(NewState))
25 | {
26 | if (String.Compare(NewState, Paths.CustomFont, StringComparison.InvariantCultureIgnoreCase) != 0 && File.Exists(NewState))
27 | {
28 | Directory.CreateDirectory(Path.GetDirectoryName(Paths.CustomFont)!);
29 |
30 | Filesystem.AssertReadOnly(Paths.CustomFont);
31 | File.Copy(NewState, Paths.CustomFont, true);
32 | }
33 | }
34 | else if (File.Exists(Paths.CustomFont))
35 | {
36 | Filesystem.AssertReadOnly(Paths.CustomFont);
37 | File.Delete(Paths.CustomFont);
38 | }
39 |
40 | OriginalState = NewState;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/ModPresetTask.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.Models.Entities;
2 | using Bloxstrap.Models.SettingTasks.Base;
3 |
4 | namespace Bloxstrap.Models.SettingTasks
5 | {
6 | public class ModPresetTask : BoolBaseTask
7 | {
8 | private Dictionary _fileDataMap = new();
9 |
10 | private Dictionary _pathMap;
11 |
12 | public ModPresetTask(string name, string path, string resource) : this(name, new() {{ path, resource }}) { }
13 |
14 | public ModPresetTask(string name, Dictionary pathMap) : base("ModPreset", name)
15 | {
16 | _pathMap = pathMap;
17 |
18 | foreach (var pair in _pathMap)
19 | {
20 | var data = new ModPresetFileData(pair.Key, pair.Value);
21 |
22 | if (data.HashMatches() && !OriginalState)
23 | OriginalState = true;
24 |
25 | _fileDataMap[pair.Key] = data;
26 | }
27 | }
28 |
29 | public override void Execute()
30 | {
31 | if (NewState == OriginalState)
32 | return;
33 |
34 | foreach (var pair in _fileDataMap)
35 | {
36 | var data = pair.Value;
37 | bool hashMatches = data.HashMatches();
38 |
39 | if (NewState && !hashMatches)
40 | {
41 | Directory.CreateDirectory(Path.GetDirectoryName(data.FullFilePath)!);
42 |
43 | using var resourceStream = data.ResourceStream;
44 | using var memoryStream = new MemoryStream();
45 | resourceStream.CopyTo(memoryStream);
46 |
47 | Filesystem.AssertReadOnly(data.FullFilePath);
48 | File.WriteAllBytes(data.FullFilePath, memoryStream.ToArray());
49 | }
50 | else if (!NewState && hashMatches)
51 | {
52 | Filesystem.AssertReadOnly(data.FullFilePath);
53 | File.Delete(data.FullFilePath);
54 | }
55 | }
56 |
57 | OriginalState = NewState;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/SettingTasks/ShortcutTask.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models.SettingTasks
2 | {
3 | public class ShortcutTask : BoolBaseTask
4 | {
5 | private string _shortcutPath;
6 |
7 | private string _exeFlags;
8 |
9 | public ShortcutTask(string name, string lnkFolder, string lnkName, string exeFlags = "") : base("Shortcut", name)
10 | {
11 | _shortcutPath = Path.Combine(lnkFolder, lnkName);
12 | _exeFlags = exeFlags;
13 |
14 | OriginalState = File.Exists(_shortcutPath);
15 | }
16 |
17 | public override void Execute()
18 | {
19 | if (NewState)
20 | Shortcut.Create(Paths.Application, _exeFlags, _shortcutPath);
21 | else if (File.Exists(_shortcutPath))
22 | File.Delete(_shortcutPath);
23 |
24 | OriginalState = NewState;
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/Bloxstrap/Models/ThumbnailCacheEntry.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models
2 | {
3 | internal class ThumbnailCacheEntry
4 | {
5 | public ulong Id { get; set; }
6 | public string Url { get; set; } = string.Empty;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Bloxstrap/Models/WatcherData.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Models
2 | {
3 | internal class WatcherData
4 | {
5 | public int ProcessId { get; set; }
6 |
7 | public string? LogFile { get; set; }
8 |
9 | public List? AutoclosePids { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Bloxstrap/MultiInstanceWatcher.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap
2 | {
3 | internal static class MultiInstanceWatcher
4 | {
5 | private static int GetOpenProcessesCount()
6 | {
7 | const string LOG_IDENT = "MultiInstanceWatcher::GetOpenProcessesCount";
8 |
9 | try
10 | {
11 | // prevent any possible race conditions by checking for bloxstrap processes too
12 | int count = Process.GetProcesses().Count(x => x.ProcessName is "RobloxPlayerBeta" or "Bloxstrap");
13 | count -= 1; // ignore the current process
14 | return count;
15 | }
16 | catch (Exception ex)
17 | {
18 | // everything process related can error at any time
19 | App.Logger.WriteException(LOG_IDENT, ex);
20 | return -1;
21 | }
22 | }
23 |
24 | private static void FireInitialisedEvent()
25 | {
26 | using EventWaitHandle initEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "Bloxstrap-MultiInstanceWatcherInitialisationFinished");
27 | initEventHandle.Set();
28 | }
29 |
30 | public static void Run()
31 | {
32 | const string LOG_IDENT = "MultiInstanceWatcher::Run";
33 |
34 | // try to get the mutex
35 | bool acquiredMutex;
36 | using Mutex mutex = new Mutex(false, "ROBLOX_singletonMutex");
37 | try
38 | {
39 | acquiredMutex = mutex.WaitOne(0);
40 | }
41 | catch (AbandonedMutexException)
42 | {
43 | acquiredMutex = true;
44 | }
45 |
46 | if (!acquiredMutex)
47 | {
48 | App.Logger.WriteLine(LOG_IDENT, "Client singleton mutex is already acquired");
49 | FireInitialisedEvent();
50 | return;
51 | }
52 |
53 | App.Logger.WriteLine(LOG_IDENT, "Acquired mutex!");
54 | FireInitialisedEvent();
55 |
56 | // watch for alive processes
57 | int count;
58 | do
59 | {
60 | Thread.Sleep(5000);
61 | count = GetOpenProcessesCount();
62 | }
63 | while (count == -1 || count > 0); // redo if -1 (one of the Process apis failed)
64 |
65 | App.Logger.WriteLine(LOG_IDENT, "All Roblox related processes have closed, exiting!");
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Bloxstrap/NativeMethods.txt:
--------------------------------------------------------------------------------
1 | SetForegroundWindow
2 | FlashWindow
3 | GetWindowLong
4 | SetWindowLong
5 | SHObjectProperties
--------------------------------------------------------------------------------
/Bloxstrap/Paths.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap
2 | {
3 | static class Paths
4 | {
5 | // note that these are directories that aren't tethered to the basedirectory
6 | // so these can safely be called before initialization
7 | public static string Temp => Path.Combine(Path.GetTempPath(), App.ProjectName);
8 | public static string UserProfile => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
9 | public static string LocalAppData => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
10 | public static string Desktop => Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
11 | public static string WindowsStartMenu => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs");
12 | public static string System => Environment.GetFolderPath(Environment.SpecialFolder.System);
13 |
14 | public static string Process => Environment.ProcessPath!;
15 |
16 | public static string TempUpdates => Path.Combine(Temp, "Updates");
17 | public static string TempLogs => Path.Combine(Temp, "Logs");
18 |
19 | public static string Base { get; private set; } = "";
20 | public static string Downloads { get; private set; } = "";
21 | public static string Logs { get; private set; } = "";
22 | public static string Integrations { get; private set; } = "";
23 | public static string Versions { get; private set; } = "";
24 | public static string Modifications { get; private set; } = "";
25 | public static string CustomThemes { get; private set; } = "";
26 |
27 | public static string Application { get; private set; } = "";
28 |
29 | public static string CustomFont => Path.Combine(Modifications, "content\\fonts\\CustomFont.ttf");
30 |
31 | public static bool Initialized => !String.IsNullOrEmpty(Base);
32 |
33 | public static void Initialize(string baseDirectory)
34 | {
35 | Base = baseDirectory;
36 | Downloads = Path.Combine(Base, "Downloads");
37 | Logs = Path.Combine(Base, "Logs");
38 | Integrations = Path.Combine(Base, "Integrations");
39 | Versions = Path.Combine(Base, "Versions");
40 | Modifications = Path.Combine(Base, "Modifications");
41 | CustomThemes = Path.Combine(Base, "CustomThemes");
42 |
43 | Application = Path.Combine(Base, $"{App.ProjectName}.exe");
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Bloxstrap/Properties/PublishProfiles/Publish-x64.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | bin\Release\net6.0-windows\publish\win-x64\
10 | FileSystem
11 | <_TargetId>Folder
12 | net6.0-windows
13 | win-x64
14 | false
15 | true
16 | false
17 |
18 |
--------------------------------------------------------------------------------
/Bloxstrap/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Bloxstrap.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.0.3.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Bloxstrap/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Bloxstrap/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Bloxstrap (Launch)": {
4 | "commandName": "Project"
5 | },
6 | "Bloxstrap (Quiet Launch)": {
7 | "commandName": "Project",
8 | "commandLineArgs": "-quiet"
9 | },
10 | "Bloxstrap (Uninstall)": {
11 | "commandName": "Project",
12 | "commandLineArgs": "-uninstall"
13 | },
14 | "Bloxstrap (Quiet Uninstall)": {
15 | "commandName": "Project",
16 | "commandLineArgs": "-uninstall -quiet"
17 | },
18 | "Bloxstrap (Menu)": {
19 | "commandName": "Project",
20 | "commandLineArgs": "-menu"
21 | },
22 | "Bloxstrap (Deeplink)": {
23 | "commandName": "Project",
24 | "commandLineArgs": "-player \"roblox://experiences/start?placeId=13700835620\""
25 | },
26 | "Bloxstrap (Studio Launch)": {
27 | "commandName": "Project",
28 | "commandLineArgs": "-studio"
29 | },
30 | "Bloxstrap (Watcher)": {
31 | "commandName": "Project",
32 | "commandLineArgs": "-watcher"
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/Bloxstrap/Resource.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace Bloxstrap
4 | {
5 | static class Resource
6 | {
7 | static readonly Assembly assembly = Assembly.GetExecutingAssembly();
8 | static readonly string[] resourceNames = assembly.GetManifestResourceNames();
9 |
10 | public static Stream GetStream(string name)
11 | {
12 | string path = resourceNames.Single(str => str.EndsWith(name));
13 | return assembly.GetManifestResourceStream(path)!;
14 | }
15 |
16 | public static async Task Get(string name)
17 | {
18 | using var stream = GetStream(name);
19 | using var memoryStream = new MemoryStream();
20 |
21 | await stream.CopyToAsync(memoryStream);
22 | return memoryStream.ToArray();
23 | }
24 |
25 | public static async Task GetString(string name)
26 | {
27 | return Encoding.UTF8.GetString(await Get(name));
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/ByfronLogoDark.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/ByfronLogoDark.jpg
--------------------------------------------------------------------------------
/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/ByfronLogoLight.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/ByfronLogoLight.jpg
--------------------------------------------------------------------------------
/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/Matt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/Matt.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/CancelButton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/CancelButton.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/CancelButtonHover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/CancelButtonHover.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/CustomBootstrapperTemplate_Blank.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Bloxstrap/Resources/DarkCancelButton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/DarkCancelButton.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/DarkCancelButtonHover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/DarkCancelButtonHover.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Fonts/NotoSansThai-VariableFont_wdth,wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Fonts/NotoSansThai-VariableFont_wdth,wght.ttf
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Fonts/Rubik-VariableFont_wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Fonts/Rubik-VariableFont_wght.ttf
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Icon2008.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Icon2008.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Icon2011.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Icon2011.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Icon2017.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Icon2017.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Icon2019.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Icon2019.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Icon2022.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Icon2022.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/IconBloxstrap.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/IconBloxstrap.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/IconBloxstrapClassic.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/IconBloxstrapClassic.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/IconEarly2015.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/IconEarly2015.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/IconLate2015.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/IconLate2015.ico
--------------------------------------------------------------------------------
/Bloxstrap/Resources/MessageBox/Error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/MessageBox/Error.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/MessageBox/FullQuality/Error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/MessageBox/FullQuality/Error.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/MessageBox/FullQuality/Information.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/MessageBox/FullQuality/Information.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/MessageBox/FullQuality/Question.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/MessageBox/FullQuality/Question.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/MessageBox/FullQuality/Warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/MessageBox/FullQuality/Warning.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/MessageBox/Information.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/MessageBox/Information.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/MessageBox/Question.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/MessageBox/Question.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/MessageBox/Warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/MessageBox/Warning.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Cursor/From2006/ArrowCursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Cursor/From2006/ArrowCursor.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Cursor/From2006/ArrowFarCursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Cursor/From2006/ArrowFarCursor.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Cursor/From2013/ArrowCursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Cursor/From2013/ArrowCursor.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Cursor/From2013/ArrowFarCursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Cursor/From2013/ArrowFarCursor.png
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/OldAvatarBackground.rbxl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/OldAvatarBackground.rbxl
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Sounds/Empty.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Sounds/Empty.mp3
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Sounds/OldDeath.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Sounds/OldDeath.ogg
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Sounds/OldGetUp.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Sounds/OldGetUp.mp3
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Sounds/OldJump.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Sounds/OldJump.mp3
--------------------------------------------------------------------------------
/Bloxstrap/Resources/Mods/Sounds/OldWalk.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Bloxstrap/Resources/Mods/Sounds/OldWalk.mp3
--------------------------------------------------------------------------------
/Bloxstrap/UI/Converters/EnumNameConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows.Data;
8 | using System.Xml.Linq;
9 |
10 | namespace Bloxstrap.UI.Converters
11 | {
12 | class EnumNameConverter : IValueConverter
13 | {
14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
15 | {
16 | // https://stackoverflow.com/a/28672015/11852173
17 |
18 | var enumVal = (Enum)value;
19 | var stringVal = enumVal.ToString();
20 |
21 | var type = enumVal.GetType();
22 | var typeName = type.FullName!;
23 | var attributes = type.GetMember(stringVal)[0].GetCustomAttributes(typeof(EnumNameAttribute), false);
24 |
25 | if (attributes.Length > 0)
26 | {
27 | var attribute = (EnumNameAttribute)attributes[0];
28 |
29 | if (attribute is not null)
30 | {
31 | if (attribute.StaticName is not null)
32 | return attribute.StaticName;
33 |
34 | if (attribute.FromTranslation is not null)
35 | return Strings.ResourceManager.GetStringSafe(attribute.FromTranslation);
36 | }
37 | }
38 |
39 | return Strings.ResourceManager.GetStringSafe(String.Format(
40 | "{0}.{1}",
41 | typeName.Substring(typeName.IndexOf('.', StringComparison.Ordinal) + 1),
42 | stringVal
43 | ));
44 | }
45 |
46 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
47 | {
48 | throw new NotSupportedException();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Converters/RangeConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Data;
2 |
3 | namespace Bloxstrap.UI.Converters
4 | {
5 | internal class RangeConverter : IValueConverter
6 | {
7 | public int? From { get; set; }
8 |
9 | public int? To { get; set; }
10 |
11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | int numvalue = (int)value;
14 |
15 | if (From is null)
16 | return numvalue < To;
17 |
18 | if (To is null)
19 | return numvalue > From;
20 |
21 | return numvalue > From && numvalue < To;
22 | }
23 |
24 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
25 | {
26 | throw new NotImplementedException();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Converters/StringFormatConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows.Data;
7 |
8 | namespace Bloxstrap.UI.Converters
9 | {
10 | public class StringFormatConverter : IValueConverter
11 | {
12 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
13 | {
14 | string? valueStr = value as string;
15 | string? parameterStr = parameter as string;
16 |
17 | if (valueStr is null)
18 | return "";
19 |
20 | if (parameterStr is null)
21 | return valueStr;
22 |
23 | string[] args = parameterStr.Split(new char[] { '|' });
24 |
25 | return string.Format(valueStr, args);
26 | }
27 |
28 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
29 | {
30 | throw new NotImplementedException(nameof(ConvertBack));
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/About/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 | using Wpf.Ui.Controls.Interfaces;
3 | using Wpf.Ui.Mvvm.Contracts;
4 |
5 | namespace Bloxstrap.UI.Elements.About
6 | {
7 | ///
8 | /// Interaction logic for MainWindow.xaml
9 | ///
10 | public partial class MainWindow : INavigationWindow
11 | {
12 | public MainWindow()
13 | {
14 | InitializeComponent();
15 |
16 | App.Logger.WriteLine("MainWindow", "Initializing about window");
17 |
18 | if (Locale.CurrentCulture.Name.StartsWith("tr"))
19 | TranslatorsText.FontSize = 9;
20 | }
21 |
22 | #region INavigationWindow methods
23 |
24 | public Frame GetFrame() => RootFrame;
25 |
26 | public INavigation GetNavigation() => RootNavigation;
27 |
28 | public bool Navigate(Type pageType) => RootNavigation.Navigate(pageType);
29 |
30 | public void SetPageService(IPageService pageService) => RootNavigation.PageService = pageService;
31 |
32 | public void ShowWindow() => Show();
33 |
34 | public void CloseWindow() => Close();
35 |
36 | #endregion INavigationWindow methods
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.UI.ViewModels.About;
2 |
3 | using System.Windows.Input;
4 | using System.Windows.Media.Animation;
5 |
6 | namespace Bloxstrap.UI.Elements.About.Pages
7 | {
8 | ///
9 | /// Interaction logic for AboutPage.xaml
10 | ///
11 | public partial class AboutPage
12 | {
13 | private readonly Queue _keys = new();
14 |
15 | private readonly List _expectedKeys = new() { Key.M, Key.A, Key.T, Key.T, Key.LeftShift, Key.D1 };
16 |
17 | private bool _triggered = false;
18 |
19 | public AboutPage()
20 | {
21 | DataContext = new AboutViewModel();
22 | InitializeComponent();
23 | }
24 |
25 | private void UiPage_KeyDown(object sender, KeyEventArgs e)
26 | {
27 | if (_triggered)
28 | return;
29 |
30 | if (_keys.Count >= 6)
31 | _keys.Dequeue();
32 |
33 | var key = e.Key;
34 |
35 | if (key == Key.RightShift)
36 | key = Key.LeftShift;
37 |
38 | _keys.Enqueue(key);
39 |
40 | if (_keys.SequenceEqual(_expectedKeys))
41 | {
42 | _triggered = true;
43 | var storyboard = Resources["EggStoryboard"] as Storyboard;
44 | storyboard!.Begin();
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/About/Pages/LicensesPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.UI.Elements.About.Pages
2 | {
3 | ///
4 | /// Interaction logic for LicensesPage.xaml
5 | ///
6 | public partial class LicensesPage
7 | {
8 | public LicensesPage()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | using Bloxstrap.UI.ViewModels.About;
4 |
5 | namespace Bloxstrap.UI.Elements.About.Pages
6 | {
7 | ///
8 | /// Interaction logic for SupportersPage.xaml
9 | ///
10 | public partial class SupportersPage
11 | {
12 | private readonly SupportersViewModel _viewModel = new();
13 |
14 | public SupportersPage()
15 | {
16 | DataContext = _viewModel;
17 | InitializeComponent();
18 | }
19 |
20 | private void UiPage_SizeChanged(object sender, SizeChangedEventArgs e)
21 | => _viewModel.WindowResizeEvent?.Invoke(sender, e);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/About/Pages/TranslatorsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.UI.Elements.About.Pages
2 | {
3 | ///
4 | /// Interaction logic for TranslatorsPage.xaml
5 | ///
6 | public partial class TranslatorsPage
7 | {
8 | public TranslatorsPage()
9 | {
10 | InitializeComponent();
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Base/WpfUiWindow.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Interop;
3 | using Wpf.Ui.Appearance;
4 | using Wpf.Ui.Controls;
5 | using Wpf.Ui.Mvvm.Contracts;
6 | using Wpf.Ui.Mvvm.Services;
7 |
8 | namespace Bloxstrap.UI.Elements.Base
9 | {
10 | public abstract class WpfUiWindow : UiWindow
11 | {
12 | private readonly IThemeService _themeService = new ThemeService();
13 |
14 | public WpfUiWindow()
15 | {
16 | ApplyTheme();
17 | }
18 |
19 | public void ApplyTheme()
20 | {
21 | const int customThemeIndex = 2; // index for CustomTheme merged dictionary
22 |
23 | _themeService.SetTheme(App.Settings.Prop.Theme.GetFinal() == Enums.Theme.Dark ? ThemeType.Dark : ThemeType.Light);
24 | _themeService.SetSystemAccent();
25 |
26 | // there doesn't seem to be a way to query the name for merged dictionaries
27 | var dict = new ResourceDictionary { Source = new Uri($"pack://application:,,,/UI/Style/{Enum.GetName(App.Settings.Prop.Theme.GetFinal())}.xaml") };
28 | Application.Current.Resources.MergedDictionaries[customThemeIndex] = dict;
29 |
30 | #if QA_BUILD
31 | this.BorderBrush = System.Windows.Media.Brushes.Red;
32 | this.BorderThickness = new Thickness(4);
33 | #endif
34 | }
35 |
36 | protected override void OnSourceInitialized(EventArgs e)
37 | {
38 | if (App.Settings.Prop.WPFSoftwareRender || App.LaunchSettings.NoGPUFlag.Active)
39 | {
40 | if (PresentationSource.FromVisual(this) is HwndSource hwndSource)
41 | hwndSource.CompositionTarget.RenderMode = RenderMode.SoftwareOnly;
42 | }
43 |
44 | base.OnSourceInitialized(e);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Bootstrapper/Base/BaseFunctions.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Bloxstrap.UI.Elements.Bootstrapper.Base
4 | {
5 | static class BaseFunctions
6 | {
7 | public static void ShowSuccess(string message, Action? callback)
8 | {
9 | Frontend.ShowMessageBox(message, MessageBoxImage.Information);
10 |
11 | if (callback is not null)
12 | callback();
13 |
14 | App.Terminate();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Bootstrapper/CustomDialog.xaml:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Bootstrapper/LegacyDialog2008.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Forms;
2 |
3 | using Bloxstrap.UI.Elements.Bootstrapper.Base;
4 |
5 | namespace Bloxstrap.UI.Elements.Bootstrapper
6 | {
7 | // windows: https://youtu.be/VpduiruysuM?t=18
8 | // mac: https://youtu.be/ncHhbcVDRgQ?t=63
9 |
10 | public partial class LegacyDialog2008 : WinFormsDialogBase
11 | {
12 | protected override string _message
13 | {
14 | get => labelMessage.Text;
15 | set => labelMessage.Text = value;
16 | }
17 |
18 | protected override ProgressBarStyle _progressStyle
19 | {
20 | get => ProgressBar.Style;
21 | set => ProgressBar.Style = value;
22 | }
23 |
24 | protected override int _progressMaximum
25 | {
26 | get => ProgressBar.Maximum;
27 | set => ProgressBar.Maximum = value;
28 | }
29 |
30 | protected override int _progressValue
31 | {
32 | get => ProgressBar.Value;
33 | set => ProgressBar.Value = value;
34 | }
35 |
36 | protected override bool _cancelEnabled
37 | {
38 | get => this.buttonCancel.Enabled;
39 | set => this.buttonCancel.Enabled = value;
40 | }
41 |
42 | public LegacyDialog2008()
43 | {
44 | InitializeComponent();
45 |
46 | this.buttonCancel.Text = Strings.Common_Cancel;
47 |
48 | ScaleWindow();
49 | SetupDialog();
50 |
51 | this.ProgressBar.RightToLeft = this.RightToLeft;
52 | this.ProgressBar.RightToLeftLayout = this.RightToLeftLayout;
53 | }
54 |
55 | private void LegacyDialog2008_Load(object sender, EventArgs e)
56 | {
57 | this.Activate();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Bootstrapper/LegacyDialog2011.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Forms;
2 |
3 | using Bloxstrap.UI.Elements.Bootstrapper.Base;
4 |
5 | namespace Bloxstrap.UI.Elements.Bootstrapper
6 | {
7 | // https://youtu.be/3K9oCEMHj2s?t=35
8 |
9 | public partial class LegacyDialog2011 : WinFormsDialogBase
10 | {
11 | protected override string _message
12 | {
13 | get => labelMessage.Text;
14 | set => labelMessage.Text = value;
15 | }
16 |
17 | protected override ProgressBarStyle _progressStyle
18 | {
19 | get => ProgressBar.Style;
20 | set => ProgressBar.Style = value;
21 | }
22 |
23 | protected override int _progressMaximum
24 | {
25 | get => ProgressBar.Maximum;
26 | set => ProgressBar.Maximum = value;
27 | }
28 |
29 | protected override int _progressValue
30 | {
31 | get => ProgressBar.Value;
32 | set => ProgressBar.Value = value;
33 | }
34 |
35 | protected override bool _cancelEnabled
36 | {
37 | get => this.buttonCancel.Enabled;
38 | set => this.buttonCancel.Enabled = this.buttonCancel.Visible = value;
39 | }
40 |
41 | public LegacyDialog2011()
42 | {
43 | InitializeComponent();
44 |
45 | this.IconBox.BackgroundImage = App.Settings.Prop.BootstrapperIcon.GetIcon().ToBitmap();
46 | this.buttonCancel.Text = Strings.Common_Cancel;
47 |
48 | ScaleWindow();
49 | SetupDialog();
50 |
51 | this.ProgressBar.RightToLeft = this.RightToLeft;
52 | this.ProgressBar.RightToLeftLayout = this.RightToLeftLayout;
53 | }
54 |
55 | private void LegacyDialog2011_Load(object sender, EventArgs e)
56 | {
57 | this.Activate();
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Bootstrapper/VistaDialog.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.UI.Elements.Bootstrapper
2 | {
3 | partial class VistaDialog
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.SuspendLayout();
32 | //
33 | // VistaDialog
34 | //
35 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
36 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
37 | this.ClientSize = new System.Drawing.Size(0, 0);
38 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
39 | this.Name = "VistaDialog";
40 | this.Opacity = 0D;
41 | this.ShowInTaskbar = false;
42 | this.Text = "VistaDialog";
43 | this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
44 | this.Load += new System.EventHandler(this.VistaDialog_Load);
45 | this.FormClosing += this.Dialog_FormClosing;
46 | this.ResumeLayout(false);
47 |
48 | }
49 |
50 | #endregion
51 | }
52 | }
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Bootstrapper/VistaDialog.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | text/microsoft-resx
50 |
51 |
52 | 2.0
53 |
54 |
55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
56 |
57 |
58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
59 |
60 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/ContextMenu/ServerHistory.xaml.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.Integrations;
2 | using Bloxstrap.UI.ViewModels.ContextMenu;
3 |
4 | namespace Bloxstrap.UI.Elements.ContextMenu
5 | {
6 | ///
7 | /// Interaction logic for ServerInformation.xaml
8 | ///
9 | public partial class ServerHistory
10 | {
11 | public ServerHistory(ActivityWatcher watcher)
12 | {
13 | var viewModel = new ServerHistoryViewModel(watcher);
14 |
15 | viewModel.RequestCloseEvent += (_, _) => Close();
16 |
17 | DataContext = viewModel;
18 | InitializeComponent();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/ContextMenu/ServerInformation.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 |
15 | using Bloxstrap.Integrations;
16 | using Bloxstrap.UI.ViewModels.ContextMenu;
17 |
18 | namespace Bloxstrap.UI.Elements.ContextMenu
19 | {
20 | ///
21 | /// Interaction logic for ServerInformation.xaml
22 | ///
23 | public partial class ServerInformation
24 | {
25 | public ServerInformation(Watcher watcher)
26 | {
27 | DataContext = new ServerInformationViewModel(watcher);
28 | InitializeComponent();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Controls/Expander.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Controls/Expander.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Markup;
12 | using System.Windows.Media;
13 | using System.Windows.Media.Imaging;
14 | using System.Windows.Navigation;
15 | using System.Windows.Shapes;
16 | using Wpf.Ui.Common;
17 |
18 | namespace Bloxstrap.UI.Elements.Controls
19 | {
20 | ///
21 | /// Interaction logic for Expander.xaml
22 | ///
23 | [ContentProperty(nameof(InnerContent))]
24 | public partial class Expander : UserControl
25 | {
26 | public static readonly DependencyProperty IsExpandedProperty =
27 | DependencyProperty.Register(nameof(IsExpanded), typeof(bool), typeof(Expander));
28 |
29 | public static readonly DependencyProperty HeaderIconProperty =
30 | DependencyProperty.Register(nameof(HeaderIcon), typeof(SymbolRegular), typeof(Expander));
31 |
32 | public static readonly DependencyProperty HeaderTextProperty =
33 | DependencyProperty.Register(nameof(HeaderText), typeof(string), typeof(Expander));
34 |
35 | public static readonly DependencyProperty InnerContentProperty =
36 | DependencyProperty.Register(nameof(InnerContent), typeof(object), typeof(Expander));
37 |
38 | public bool IsExpanded
39 | {
40 | get { return (bool)GetValue(IsExpandedProperty); }
41 | set { SetValue(IsExpandedProperty, value); }
42 | }
43 |
44 | public string HeaderText
45 | {
46 | get { return (string)GetValue(HeaderTextProperty); }
47 | set { SetValue(HeaderTextProperty, value); }
48 | }
49 |
50 | public SymbolRegular HeaderIcon
51 | {
52 | get { return (SymbolRegular)GetValue(HeaderIconProperty); }
53 | set { SetValue(HeaderTextProperty, value); }
54 | }
55 |
56 | public object InnerContent
57 | {
58 | get { return GetValue(InnerContentProperty); }
59 | set { SetValue(InnerContentProperty, value); }
60 | }
61 |
62 | public Expander()
63 | {
64 | InitializeComponent();
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Controls/OptionControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Markup;
12 | using System.Windows.Media;
13 | using System.Windows.Media.Imaging;
14 | using System.Windows.Navigation;
15 | using System.Windows.Shapes;
16 |
17 | namespace Bloxstrap.UI.Elements.Controls
18 | {
19 | ///
20 | /// Interaction logic for OptionControl.xaml
21 | ///
8 | /// Interaction logic for AddFastFlagDialog.xaml
9 | ///
10 | public partial class AddFastFlagDialog
11 | {
12 | public MessageBoxResult Result = MessageBoxResult.Cancel;
13 |
14 | public AddFastFlagDialog()
15 | {
16 | InitializeComponent();
17 | }
18 |
19 | private void ImportButton_Click(object sender, RoutedEventArgs e)
20 | {
21 | var dialog = new OpenFileDialog
22 | {
23 | Filter = $"{Strings.FileTypes_JSONFiles}|*.json"
24 | };
25 |
26 | if (dialog.ShowDialog() != true)
27 | return;
28 |
29 | JsonTextBox.Text = File.ReadAllText(dialog.FileName);
30 | }
31 |
32 | private void OKButton_Click(object sender, RoutedEventArgs e)
33 | {
34 | Result = MessageBoxResult.OK;
35 | Close();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Dialogs/FluentMessageBox.xaml:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Dialogs/LanguageSelectorDialog.xaml:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Dialogs/LanguageSelectorDialog.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 | using Bloxstrap.UI.ViewModels.Dialogs;
15 |
16 | namespace Bloxstrap.UI.Elements.Dialogs
17 | {
18 | ///
19 | /// Interaction logic for LanguageSelectorDialog.xaml
20 | ///
21 | public partial class LanguageSelectorDialog
22 | {
23 | public LanguageSelectorDialog()
24 | {
25 | var viewModel = new LanguageSelectorViewModel();
26 |
27 | DataContext = viewModel;
28 | InitializeComponent();
29 |
30 | viewModel.CloseRequestEvent += (_, _) => Close();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Dialogs/LaunchMenuDialog.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 | using Bloxstrap.UI.ViewModels.Dialogs;
15 | using Bloxstrap.UI.ViewModels.Installer;
16 | using Wpf.Ui.Mvvm.Interfaces;
17 |
18 | namespace Bloxstrap.UI.Elements.Dialogs
19 | {
20 | ///
21 | /// Interaction logic for LaunchMenuDialog.xaml
22 | ///
23 | public partial class LaunchMenuDialog
24 | {
25 | public NextAction CloseAction = NextAction.Terminate;
26 |
27 | public LaunchMenuDialog()
28 | {
29 | var viewModel = new LaunchMenuViewModel();
30 | viewModel.CloseWindowRequest += (_, closeAction) =>
31 | {
32 | CloseAction = closeAction;
33 | Close();
34 | };
35 |
36 | DataContext = viewModel;
37 |
38 | InitializeComponent();
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Dialogs/UninstallerDialog.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 | using Bloxstrap.UI.ViewModels.Dialogs;
15 | using Bloxstrap.UI.ViewModels.Installer;
16 | using Wpf.Ui.Mvvm.Interfaces;
17 |
18 | namespace Bloxstrap.UI.Elements.Dialogs
19 | {
20 | ///
21 | /// Interaction logic for UninstallerDialog.xaml
22 | ///
23 | public partial class UninstallerDialog
24 | {
25 | public bool Confirmed { get; private set; } = false;
26 |
27 | public bool KeepData { get; private set; } = true;
28 |
29 | public UninstallerDialog()
30 | {
31 | var viewModel = new UninstallerViewModel();
32 | viewModel.ConfirmUninstallRequest += (_, _) =>
33 | {
34 | Confirmed = true;
35 | KeepData = viewModel.KeepData;
36 | Close();
37 | };
38 |
39 | DataContext = viewModel;
40 |
41 | InitializeComponent();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Installer/Pages/CompletionPage.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Installer/Pages/CompletionPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using Bloxstrap.UI.ViewModels.Installer;
3 |
4 | namespace Bloxstrap.UI.Elements.Installer.Pages
5 | {
6 | ///
7 | /// Interaction logic for CompletionPage.xaml
8 | ///
9 | public partial class CompletionPage
10 | {
11 | private readonly CompletionViewModel _viewModel = new();
12 | public CompletionPage()
13 | {
14 | _viewModel.CloseWindowRequest += (_, closeAction) =>
15 | {
16 | if (Window.GetWindow(this) is MainWindow window)
17 | {
18 | window.CloseAction = closeAction;
19 | window.Close();
20 | }
21 | };
22 |
23 | DataContext = _viewModel;
24 | InitializeComponent();
25 | }
26 |
27 | private void UiPage_Loaded(object sender, RoutedEventArgs e)
28 | {
29 | if (Window.GetWindow(this) is MainWindow window)
30 | {
31 | window.SetNextButtonText(Strings.Common_Navigation_Next);
32 | window.SetButtonEnabled("back", false);
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Installer/Pages/InstallPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | using Bloxstrap.UI.ViewModels.Installer;
5 |
6 | namespace Bloxstrap.UI.Elements.Installer.Pages
7 | {
8 | ///
9 | /// Interaction logic for WelcomePage.xaml
10 | ///
11 | public partial class InstallPage
12 | {
13 | private readonly InstallViewModel _viewModel = new();
14 |
15 | public InstallPage()
16 | {
17 | DataContext = _viewModel;
18 |
19 | _viewModel.SetCanContinueEvent += (_, state) =>
20 | {
21 | if (Window.GetWindow(this) is MainWindow window)
22 | window.SetButtonEnabled("next", state);
23 | };
24 |
25 | InitializeComponent();
26 | }
27 |
28 | private void UiPage_Loaded(object sender, RoutedEventArgs e)
29 | {
30 | if (Window.GetWindow(this) is MainWindow window)
31 | {
32 | window.SetNextButtonText(Strings.Common_Navigation_Install);
33 | window.NextPageCallback += NextPageCallback;
34 | }
35 | }
36 |
37 | public bool NextPageCallback() => _viewModel.DoInstall();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Installer/Pages/WelcomePage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using Bloxstrap.UI.ViewModels.Installer;
3 |
4 | namespace Bloxstrap.UI.Elements.Installer.Pages
5 | {
6 | ///
7 | /// Interaction logic for WelcomePage.xaml
8 | ///
9 | public partial class WelcomePage
10 | {
11 | private readonly WelcomeViewModel _viewModel = new();
12 |
13 | public WelcomePage()
14 | {
15 | _viewModel.CanContinueEvent += (_, _) =>
16 | {
17 | if (Window.GetWindow(this) is MainWindow window)
18 | window.SetButtonEnabled("next", true);
19 | };
20 |
21 | DataContext = _viewModel;
22 | InitializeComponent();
23 | }
24 |
25 | private void UiPage_Loaded(object sender, RoutedEventArgs e)
26 | {
27 | if (Window.GetWindow(this) is MainWindow window)
28 | window.SetNextButtonText(Strings.Common_Navigation_Next);
29 |
30 | _viewModel.DoChecks();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/AppearancePage.xaml.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.UI.ViewModels.Settings;
2 |
3 | using System.Windows.Controls;
4 |
5 | namespace Bloxstrap.UI.Elements.Settings.Pages
6 | {
7 | ///
8 | /// Interaction logic for AppearancePage.xaml
9 | ///
10 | public partial class AppearancePage
11 | {
12 | public AppearancePage()
13 | {
14 | DataContext = new AppearanceViewModel(this);
15 | InitializeComponent();
16 | }
17 |
18 | public void CustomThemeSelection(object sender, SelectionChangedEventArgs e)
19 | {
20 | AppearanceViewModel viewModel = (AppearanceViewModel)DataContext;
21 |
22 | viewModel.SelectedCustomTheme = (string)((ListBox)sender).SelectedItem;
23 | viewModel.SelectedCustomThemeName = viewModel.SelectedCustomTheme;
24 |
25 | viewModel.OnPropertyChanged(nameof(viewModel.SelectedCustomTheme));
26 | viewModel.OnPropertyChanged(nameof(viewModel.SelectedCustomThemeName));
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Bloxstrap.UI.ViewModels.Settings;
7 |
8 | namespace Bloxstrap.UI.Elements.Settings.Pages
9 | {
10 | ///
11 | /// Interaction logic for BloxstrapPage.xaml
12 | ///
13 | public partial class BloxstrapPage
14 | {
15 | public BloxstrapPage()
16 | {
17 | DataContext = new BloxstrapViewModel();
18 | InitializeComponent();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/BootstrapperPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | using Bloxstrap.UI.ViewModels.Settings;
17 |
18 | namespace Bloxstrap.UI.Elements.Settings.Pages
19 | {
20 | ///
21 | /// Interaction logic for BehaviourPage.xaml
22 | ///
23 | public partial class BehaviourPage
24 | {
25 | public BehaviourPage()
26 | {
27 | DataContext = new BehaviourViewModel();
28 | InitializeComponent();
29 | }
30 |
31 | private void ToggleSwitch_Checked(object sender, RoutedEventArgs e)
32 | {
33 |
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/FastFlagEditorWarningPage.xaml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/FastFlagEditorWarningPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.UI.ViewModels.Settings;
2 | using System.Windows;
3 |
4 | namespace Bloxstrap.UI.Elements.Settings.Pages
5 | {
6 | ///
7 | /// Interaction logic for FastFlagEditorWarningPage.xaml
8 | ///
9 | public partial class FastFlagEditorWarningPage
10 | {
11 | private FastFlagEditorWarningViewModel _viewModel;
12 |
13 | public FastFlagEditorWarningPage()
14 | {
15 | _viewModel = new FastFlagEditorWarningViewModel(this);
16 | DataContext = _viewModel;
17 |
18 | InitializeComponent();
19 | }
20 |
21 | private void Page_Loaded(object sender, RoutedEventArgs e)
22 | {
23 | _viewModel.StartCountdown();
24 | }
25 |
26 | private void Page_Unloaded(object sender, RoutedEventArgs e)
27 | {
28 | _viewModel.StopCountdown();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/FastFlagsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 |
4 | using Bloxstrap.UI.ViewModels.Settings;
5 | using Wpf.Ui.Mvvm.Contracts;
6 |
7 | namespace Bloxstrap.UI.Elements.Settings.Pages
8 | {
9 | ///
10 | /// Interaction logic for FastFlagsPage.xaml
11 | ///
12 | public partial class FastFlagsPage
13 | {
14 | private bool _initialLoad = false;
15 |
16 | private FastFlagsViewModel _viewModel = null!;
17 |
18 | public FastFlagsPage()
19 | {
20 | SetupViewModel();
21 | InitializeComponent();
22 | }
23 |
24 | private void SetupViewModel()
25 | {
26 | _viewModel = new FastFlagsViewModel();
27 |
28 | _viewModel.OpenFlagEditorEvent += OpenFlagEditor;
29 | _viewModel.RequestPageReloadEvent += (_, _) => SetupViewModel();
30 |
31 | DataContext = _viewModel;
32 | }
33 |
34 | private void OpenFlagEditor(object? sender, EventArgs e)
35 | {
36 | if (Window.GetWindow(this) is INavigationWindow window)
37 | {
38 | if (App.State.Prop.ShowFFlagEditorWarning)
39 | window.Navigate(typeof(FastFlagEditorWarningPage));
40 | else
41 | window.Navigate(typeof(FastFlagEditorPage));
42 | }
43 | }
44 |
45 | private void Page_Loaded(object sender, RoutedEventArgs e)
46 | {
47 | // refresh datacontext on page load to synchronize with editor page
48 |
49 | if (!_initialLoad)
50 | {
51 | _initialLoad = true;
52 | return;
53 | }
54 |
55 | SetupViewModel();
56 | }
57 |
58 | private void ValidateInt32(object sender, TextCompositionEventArgs e) => e.Handled = e.Text != "-" && !Int32.TryParse(e.Text, out int _);
59 |
60 | private void ValidateUInt32(object sender, TextCompositionEventArgs e) => e.Handled = !UInt32.TryParse(e.Text, out uint _);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/IntegrationsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | using Bloxstrap.UI.ViewModels.Settings;
4 |
5 | namespace Bloxstrap.UI.Elements.Settings.Pages
6 | {
7 | ///
8 | /// Interaction logic for IntegrationsPage.xaml
9 | ///
10 | public partial class IntegrationsPage
11 | {
12 | public IntegrationsPage()
13 | {
14 | DataContext = new IntegrationsViewModel();
15 | InitializeComponent();
16 | }
17 |
18 | public void CustomIntegrationSelection(object sender, SelectionChangedEventArgs e)
19 | {
20 | IntegrationsViewModel viewModel = (IntegrationsViewModel)DataContext;
21 | viewModel.SelectedCustomIntegration = (CustomIntegration)((ListBox)sender).SelectedItem;
22 | viewModel.OnPropertyChanged(nameof(viewModel.SelectedCustomIntegration));
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/ModsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using Bloxstrap.UI.ViewModels.Settings;
2 |
3 | namespace Bloxstrap.UI.Elements.Settings.Pages
4 | {
5 | ///
6 | /// Interaction logic for ModsPage.xaml
7 | ///
8 | public partial class ModsPage
9 | {
10 | public ModsPage()
11 | {
12 | DataContext = new ModsViewModel();
13 | InitializeComponent();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Elements/Settings/Pages/ShortcutsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | using Bloxstrap.UI.ViewModels.Settings;
17 |
18 | namespace Bloxstrap.UI.Elements.Settings.Pages
19 | {
20 | ///
21 | /// Interaction logic for ShortcutsPage.xaml
22 | ///
23 | public partial class ShortcutsPage
24 | {
25 | public ShortcutsPage()
26 | {
27 | DataContext = new ShortcutsViewModel();
28 | InitializeComponent();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/IBootstrapperDialog.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Forms;
2 | using System.Windows.Shell;
3 |
4 | namespace Bloxstrap.UI
5 | {
6 | public interface IBootstrapperDialog
7 | {
8 | public Bootstrapper? Bootstrapper { get; set; }
9 |
10 | string Message { get; set; }
11 | ProgressBarStyle ProgressStyle { get; set; }
12 | int ProgressValue { get; set; }
13 | int ProgressMaximum { get; set; }
14 | TaskbarItemProgressState TaskbarProgressState { get; set; }
15 | double TaskbarProgressValue { get; set; }
16 | bool CancelEnabled { get; set; }
17 |
18 | void ShowBootstrapper();
19 | void CloseBootstrapper();
20 | void ShowSuccess(string message, Action? callback = null);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Style/Dark.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Style/Editor-Theme-Dark.xshd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | <!--
15 | -->
16 |
17 |
18 | <!\[CDATA\[
19 | ]]>
20 |
21 |
22 | <!DOCTYPE
23 | >
24 |
25 |
26 | <\?
27 | \?>
28 |
29 |
30 | <
31 | >
32 |
33 |
35 |
36 | "
37 | "|(?=<)
38 |
39 |
40 | '
41 | '|(?=<)
42 |
43 | [\d\w_\-\.]+(?=(\s*=))
44 | =
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | &
53 | [\w\d\#]+
54 | ;
55 |
56 |
57 |
58 | &
59 | [\w\d\#]*
60 | #missing ;
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Style/Editor-Theme-Light.xshd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | <!--
15 | -->
16 |
17 |
18 | <!\[CDATA\[
19 | ]]>
20 |
21 |
22 | <!DOCTYPE
23 | >
24 |
25 |
26 | <\?
27 | \?>
28 |
29 |
30 | <
31 | >
32 |
33 |
35 |
36 | "
37 | "|(?=<)
38 |
39 |
40 | '
41 | '|(?=<)
42 |
43 | [\d\w_\-\.]+(?=(\s*=))
44 | =
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | &
53 | [\w\d\#]+
54 | ;
55 |
56 |
57 |
58 | &
59 | [\w\d\#]*
60 | #missing ;
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Style/Light.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Utility/Rendering.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Media;
5 |
6 | namespace Bloxstrap.UI.Utility
7 | {
8 | static class Rendering
9 | {
10 | public static double GetTextWidth(TextBlock textBlock)
11 | {
12 | return new FormattedText(
13 | textBlock.Text,
14 | CultureInfo.CurrentCulture,
15 | FlowDirection.LeftToRight,
16 | new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch),
17 | textBlock.FontSize,
18 | Brushes.Black,
19 | new NumberSubstitution(),
20 | VisualTreeHelper.GetDpi(textBlock).PixelsPerDip
21 | ).Width;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/Utility/WindowScaling.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Forms;
3 |
4 | namespace Bloxstrap.UI.Utility
5 | {
6 | public static class WindowScaling
7 | {
8 | public static double ScaleFactor => Screen.PrimaryScreen.Bounds.Width / SystemParameters.PrimaryScreenWidth;
9 |
10 | public static int GetScaledNumber(int number)
11 | {
12 | return (int)Math.Ceiling(number * ScaleFactor);
13 | }
14 |
15 | public static System.Drawing.Size GetScaledSize(System.Drawing.Size size)
16 | {
17 | return new System.Drawing.Size(GetScaledNumber(size.Width), GetScaledNumber(size.Height));
18 | }
19 |
20 | public static System.Drawing.Point GetScaledPoint(System.Drawing.Point point)
21 | {
22 | return new System.Drawing.Point(GetScaledNumber(point.X), GetScaledNumber(point.Y));
23 | }
24 |
25 | public static Padding GetScaledPadding(Padding padding)
26 | {
27 | return new Padding(GetScaledNumber(padding.Left), GetScaledNumber(padding.Top), GetScaledNumber(padding.Right), GetScaledNumber(padding.Bottom));
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/About/AboutViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Bloxstrap.UI.ViewModels.About
4 | {
5 | public class AboutViewModel : NotifyPropertyChangedViewModel
6 | {
7 | public string Version => string.Format(Strings.Menu_About_Version, App.Version);
8 |
9 | public BuildMetadataAttribute BuildMetadata => App.BuildMetadata;
10 |
11 | public string BuildTimestamp => BuildMetadata.Timestamp.ToFriendlyString();
12 | public string BuildCommitHashUrl => $"https://github.com/{App.ProjectRepository}/commit/{BuildMetadata.CommitHash}";
13 |
14 | public Visibility BuildInformationVisibility => App.IsProductionBuild ? Visibility.Collapsed : Visibility.Visible;
15 | public Visibility BuildCommitVisibility => App.IsActionBuild ? Visibility.Visible : Visibility.Collapsed;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/About/SupportersViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Bloxstrap.UI.ViewModels.About
4 | {
5 | public class SupportersViewModel : NotifyPropertyChangedViewModel
6 | {
7 | public SupporterData? SupporterData { get; private set; }
8 |
9 | public GenericTriState LoadedState { get; set; } = GenericTriState.Unknown;
10 |
11 | public string LoadError { get; set; } = "";
12 |
13 | public int Columns { get; set; } = 3;
14 |
15 | public SizeChangedEventHandler? WindowResizeEvent;
16 |
17 | public SupportersViewModel()
18 | {
19 | WindowResizeEvent += OnWindowResize;
20 |
21 | // this will cause momentary freezes only when ran under the debugger
22 | LoadSupporterData();
23 | }
24 |
25 | private void OnWindowResize(object sender, SizeChangedEventArgs e)
26 | {
27 | if (!e.WidthChanged)
28 | return;
29 |
30 | int newCols = (int)Math.Floor(e.NewSize.Width / 200);
31 |
32 | if (Columns == newCols)
33 | return;
34 |
35 | Columns = newCols;
36 | OnPropertyChanged(nameof(Columns));
37 | }
38 |
39 | public async void LoadSupporterData()
40 | {
41 | const string LOG_IDENT = "AboutViewModel::LoadSupporterData";
42 |
43 | try
44 | {
45 | SupporterData = await Http.GetJson("https://raw.githubusercontent.com/bloxstraplabs/config/main/supporters.json");
46 | }
47 | catch (Exception ex)
48 | {
49 | App.Logger.WriteLine(LOG_IDENT, "Could not load supporter data");
50 | App.Logger.WriteException(LOG_IDENT, ex);
51 |
52 | LoadedState = GenericTriState.Failed;
53 | LoadError = ex.Message;
54 |
55 | OnPropertyChanged(nameof(LoadError));
56 | }
57 |
58 | if (SupporterData is not null)
59 | {
60 | LoadedState = GenericTriState.Successful;
61 |
62 | OnPropertyChanged(nameof(SupporterData));
63 | }
64 |
65 | OnPropertyChanged(nameof(LoadedState));
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Bootstrapper/BootstrapperDialogViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 | using System.Windows.Media;
4 | using System.Windows.Shell;
5 |
6 | using CommunityToolkit.Mvvm.Input;
7 |
8 | namespace Bloxstrap.UI.ViewModels.Bootstrapper
9 | {
10 | public class BootstrapperDialogViewModel : NotifyPropertyChangedViewModel
11 | {
12 | private readonly IBootstrapperDialog _dialog;
13 |
14 | public ICommand CancelInstallCommand => new RelayCommand(CancelInstall);
15 |
16 | public string Title => App.Settings.Prop.BootstrapperTitle;
17 | public ImageSource Icon { get; set; } = App.Settings.Prop.BootstrapperIcon.GetIcon().GetImageSource();
18 | public string Message { get; set; } = "Please wait...";
19 | public bool ProgressIndeterminate { get; set; } = true;
20 | public int ProgressMaximum { get; set; } = 0;
21 | public int ProgressValue { get; set; } = 0;
22 |
23 | public TaskbarItemProgressState TaskbarProgressState { get; set; } = TaskbarItemProgressState.Indeterminate;
24 | public double TaskbarProgressValue { get; set; } = 0;
25 |
26 | public bool CancelEnabled { get; set; } = false;
27 | public Visibility CancelButtonVisibility => CancelEnabled ? Visibility.Visible : Visibility.Collapsed;
28 |
29 | [Obsolete("Do not use this! This is for the designer only.", true)]
30 | public BootstrapperDialogViewModel()
31 | {
32 | _dialog = null!;
33 | }
34 |
35 | public BootstrapperDialogViewModel(IBootstrapperDialog dialog)
36 | {
37 | _dialog = dialog;
38 | }
39 |
40 | private void CancelInstall()
41 | {
42 | _dialog.Bootstrapper?.Cancel();
43 | _dialog.CloseBootstrapper();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Bootstrapper/ByfronDialogViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Media;
3 | using System.Windows.Media.Imaging;
4 |
5 | namespace Bloxstrap.UI.ViewModels.Bootstrapper
6 | {
7 | public class ByfronDialogViewModel : BootstrapperDialogViewModel
8 | {
9 | // Using dark theme for default values.
10 | public ImageSource ByfronLogoLocation { get; set; } = new BitmapImage(new Uri("pack://application:,,,/Resources/BootstrapperStyles/ByfronDialog/ByfronLogoDark.jpg"));
11 | public Thickness DialogBorder { get; set; } = new Thickness(0);
12 | public Brush Background { get; set; } = Brushes.Black;
13 | public Brush Foreground { get; set; } = new SolidColorBrush(Color.FromRgb(239, 239, 239));
14 | public Brush IconColor { get; set; } = new SolidColorBrush(Color.FromRgb(255, 255, 255));
15 | public Brush ProgressBarBackground { get; set; } = new SolidColorBrush(Color.FromRgb(86, 86, 86));
16 |
17 | public Visibility VersionTextVisibility => CancelEnabled ? Visibility.Collapsed : Visibility.Visible;
18 |
19 | public string VersionText { get; init; }
20 |
21 | public ByfronDialogViewModel(IBootstrapperDialog dialog, string version) : base(dialog)
22 | {
23 | VersionText = version;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Bootstrapper/ClassicFluentDialogViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Media;
3 | using System.Windows.Media.Imaging;
4 |
5 | namespace Bloxstrap.UI.ViewModels.Bootstrapper
6 | {
7 | public class ClassicFluentDialogViewModel : BootstrapperDialogViewModel
8 | {
9 | public double FooterOpacity => Environment.OSVersion.Version.Build >= 22000 ? 0.4 : 1;
10 |
11 | public ClassicFluentDialogViewModel(IBootstrapperDialog dialog) : base(dialog)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Bootstrapper/FluentDialogViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows.Media;
7 | using Wpf.Ui.Appearance;
8 |
9 | namespace Bloxstrap.UI.ViewModels.Bootstrapper
10 | {
11 | public class FluentDialogViewModel : BootstrapperDialogViewModel
12 | {
13 | public BackgroundType WindowBackdropType { get; set; } = BackgroundType.Mica;
14 |
15 | public SolidColorBrush BackgroundColourBrush { get; set; } = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0));
16 |
17 | [Obsolete("Do not use this! This is for the designer only.", true)]
18 | public FluentDialogViewModel() : base()
19 | { }
20 |
21 | public FluentDialogViewModel(IBootstrapperDialog dialog, bool aero) : base(dialog)
22 | {
23 | const int alpha = 128;
24 |
25 | WindowBackdropType = aero ? BackgroundType.Aero : BackgroundType.Mica;
26 |
27 | if (aero)
28 | {
29 | BackgroundColourBrush = App.Settings.Prop.Theme.GetFinal() == Enums.Theme.Light ?
30 | new SolidColorBrush(Color.FromArgb(alpha, 225, 225, 225)) :
31 | new SolidColorBrush(Color.FromArgb(alpha, 30, 30, 30));
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/ContextMenu/ServerInformationViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 | using Bloxstrap.Integrations;
4 | using CommunityToolkit.Mvvm.Input;
5 |
6 | namespace Bloxstrap.UI.ViewModels.ContextMenu
7 | {
8 | internal class ServerInformationViewModel : NotifyPropertyChangedViewModel
9 | {
10 | private readonly ActivityWatcher _activityWatcher;
11 |
12 | public string InstanceId => _activityWatcher.Data.JobId;
13 |
14 | public string ServerType => _activityWatcher.Data.ServerType.ToTranslatedString();
15 |
16 | public string ServerLocation { get; private set; } = Strings.Common_Loading;
17 |
18 | public Visibility ServerLocationVisibility => App.Settings.Prop.ShowServerDetails ? Visibility.Visible : Visibility.Collapsed;
19 |
20 | public ICommand CopyInstanceIdCommand => new RelayCommand(CopyInstanceId);
21 |
22 | public ServerInformationViewModel(Watcher watcher)
23 | {
24 | _activityWatcher = watcher.ActivityWatcher!;
25 |
26 | if (ServerLocationVisibility == Visibility.Visible)
27 | QueryServerLocation();
28 | }
29 |
30 | public async void QueryServerLocation()
31 | {
32 | string? location = await _activityWatcher.Data.QueryServerLocation();
33 |
34 | if (String.IsNullOrEmpty(location))
35 | ServerLocation = Strings.Common_NotAvailable;
36 | else
37 | ServerLocation = location;
38 |
39 | OnPropertyChanged(nameof(ServerLocation));
40 | }
41 |
42 | private void CopyInstanceId() => Clipboard.SetDataObject(InstanceId);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Dialogs/AddCustomThemeViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 |
8 | namespace Bloxstrap.UI.ViewModels.Dialogs
9 | {
10 | internal class AddCustomThemeViewModel : NotifyPropertyChangedViewModel
11 | {
12 | public static CustomThemeTemplate[] Templates => Enum.GetValues();
13 |
14 | public CustomThemeTemplate Template { get; set; } = CustomThemeTemplate.Simple;
15 |
16 | public string Name { get; set; } = "";
17 |
18 | private string _filePath = "";
19 | public string FilePath
20 | {
21 | get => _filePath;
22 | set
23 | {
24 | if (_filePath != value)
25 | {
26 | _filePath = value;
27 | OnPropertyChanged(nameof(FilePath));
28 | OnPropertyChanged(nameof(FilePathVisibility));
29 | }
30 | }
31 | }
32 | public Visibility FilePathVisibility => string.IsNullOrEmpty(FilePath) ? Visibility.Collapsed : Visibility.Visible;
33 |
34 | public int SelectedTab { get; set; } = 0;
35 |
36 | private string _nameError = "";
37 | public string NameError
38 | {
39 | get => _nameError;
40 | set
41 | {
42 | if (_nameError != value)
43 | {
44 | _nameError = value;
45 | OnPropertyChanged(nameof(NameError));
46 | OnPropertyChanged(nameof(NameErrorVisibility));
47 | }
48 | }
49 | }
50 | public Visibility NameErrorVisibility => string.IsNullOrEmpty(NameError) ? Visibility.Collapsed : Visibility.Visible;
51 |
52 | private string _fileError = "";
53 | public string FileError
54 | {
55 | get => _fileError;
56 | set
57 | {
58 | if (_fileError != value)
59 | {
60 | _fileError = value;
61 | OnPropertyChanged(nameof(FileError));
62 | OnPropertyChanged(nameof(FileErrorVisibility));
63 | }
64 | }
65 | }
66 | public Visibility FileErrorVisibility => string.IsNullOrEmpty(FileError) ? Visibility.Collapsed : Visibility.Visible;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Dialogs/LanguageSelectorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows.Input;
7 |
8 | using CommunityToolkit.Mvvm.Input;
9 |
10 | namespace Bloxstrap.UI.ViewModels.Dialogs
11 | {
12 | internal class LanguageSelectorViewModel
13 | {
14 | public event EventHandler? CloseRequestEvent;
15 |
16 | public ICommand SetLocaleCommand => new RelayCommand(SetLocale);
17 |
18 | public static List Languages => Locale.GetLanguages();
19 |
20 | public string SelectedLanguage { get; set; } = Locale.SupportedLocales[App.Settings.Prop.Locale];
21 |
22 | private void SetLocale()
23 | {
24 | string identifier = Locale.GetIdentifierFromName(SelectedLanguage);
25 |
26 | Locale.Set(identifier);
27 | App.Settings.Prop.Locale = identifier;
28 |
29 | CloseRequestEvent?.Invoke(this, new());
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Dialogs/LaunchMenuViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 | using CommunityToolkit.Mvvm.Input;
4 |
5 | using Bloxstrap.UI.Elements.About;
6 |
7 | namespace Bloxstrap.UI.ViewModels.Installer
8 | {
9 | public class LaunchMenuViewModel
10 | {
11 | public string Version => string.Format(Strings.Menu_About_Version, App.Version);
12 |
13 | public Visibility RobloxStudioOptionVisibility => App.IsStudioVisible ? Visibility.Visible : Visibility.Collapsed;
14 |
15 | public ICommand LaunchSettingsCommand => new RelayCommand(LaunchSettings);
16 |
17 | public ICommand LaunchRobloxCommand => new RelayCommand(LaunchRoblox);
18 |
19 | public ICommand LaunchRobloxStudioCommand => new RelayCommand(LaunchRobloxStudio);
20 |
21 | public ICommand LaunchAboutCommand => new RelayCommand(LaunchAbout);
22 |
23 | public event EventHandler? CloseWindowRequest;
24 |
25 | private void LaunchSettings() => CloseWindowRequest?.Invoke(this, NextAction.LaunchSettings);
26 |
27 | private void LaunchRoblox() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRoblox);
28 |
29 | private void LaunchRobloxStudio() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRobloxStudio);
30 |
31 | private void LaunchAbout() => new MainWindow().ShowDialog();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Dialogs/UninstallerViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Input;
2 | using CommunityToolkit.Mvvm.Input;
3 |
4 | using Bloxstrap.Resources;
5 |
6 | namespace Bloxstrap.UI.ViewModels.Dialogs
7 | {
8 | public class UninstallerViewModel
9 | {
10 | public string Text => String.Format(
11 | Strings.Uninstaller_Text,
12 | "https://github.com/bloxstraplabs/bloxstrap/wiki/Roblox-crashes-or-does-not-launch",
13 | Paths.Base
14 | );
15 |
16 | public bool KeepData { get; set; } = true;
17 |
18 | public ICommand ConfirmUninstallCommand => new RelayCommand(ConfirmUninstall);
19 |
20 | public event EventHandler? ConfirmUninstallRequest;
21 |
22 | private void ConfirmUninstall() => ConfirmUninstallRequest?.Invoke(this, new EventArgs());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/GlobalViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Input;
2 | using CommunityToolkit.Mvvm.Input;
3 |
4 | namespace Bloxstrap.UI.ViewModels
5 | {
6 | public static class GlobalViewModel
7 | {
8 | public static ICommand OpenWebpageCommand => new RelayCommand(OpenWebpage);
9 |
10 | private static void OpenWebpage(string? location)
11 | {
12 | if (location is null)
13 | return;
14 |
15 | Utilities.ShellExecute(location);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Installer/CompletionViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 | using CommunityToolkit.Mvvm.Input;
4 |
5 | using Bloxstrap.Resources;
6 |
7 | using Microsoft.Win32;
8 |
9 | namespace Bloxstrap.UI.ViewModels.Installer
10 | {
11 | public class CompletionViewModel
12 | {
13 | public ICommand LaunchSettingsCommand => new RelayCommand(LaunchSettings);
14 |
15 | public ICommand LaunchRobloxCommand => new RelayCommand(LaunchRoblox);
16 |
17 | public event EventHandler? CloseWindowRequest;
18 |
19 | private void LaunchSettings() => CloseWindowRequest?.Invoke(this, NextAction.LaunchSettings);
20 |
21 | private void LaunchRoblox() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRoblox);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Installer/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Input;
2 | using CommunityToolkit.Mvvm.Input;
3 |
4 | namespace Bloxstrap.UI.ViewModels.Installer
5 | {
6 | public class MainWindowViewModel : NotifyPropertyChangedViewModel
7 | {
8 | public string NextButtonText { get; private set; } = Strings.Common_Navigation_Next;
9 |
10 | public bool BackButtonEnabled { get; private set; } = false;
11 |
12 | public bool NextButtonEnabled { get; private set; } = false;
13 |
14 | public int ButtonWidth { get; } = Locale.CurrentCulture.Name.StartsWith("bg") ? 112 : 96;
15 |
16 | public ICommand BackPageCommand => new RelayCommand(BackPage);
17 |
18 | public ICommand NextPageCommand => new RelayCommand(NextPage);
19 |
20 | public ICommand CloseWindowCommand => new RelayCommand(CloseWindow);
21 |
22 | public event EventHandler? PageRequest;
23 |
24 | public event EventHandler? CloseWindowRequest;
25 |
26 | public void SetButtonEnabled(string type, bool state)
27 | {
28 | if (type == "next")
29 | {
30 | NextButtonEnabled = state;
31 | OnPropertyChanged(nameof(NextButtonEnabled));
32 | }
33 | else if (type == "back")
34 | {
35 | BackButtonEnabled = state;
36 | OnPropertyChanged(nameof(BackButtonEnabled));
37 | }
38 | }
39 |
40 | public void SetNextButtonText(string text)
41 | {
42 | NextButtonText = text;
43 | OnPropertyChanged(nameof(NextButtonText));
44 | }
45 |
46 | private void BackPage() => PageRequest?.Invoke(this, "back");
47 |
48 | private void NextPage() => PageRequest?.Invoke(this, "next");
49 |
50 | private void CloseWindow() => CloseWindowRequest?.Invoke(this, new EventArgs());
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Installer/WelcomeViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.UI.ViewModels.Installer
2 | {
3 | public class WelcomeViewModel : NotifyPropertyChangedViewModel
4 | {
5 | // formatting is done here instead of in xaml, it's just a bit easier
6 | public string MainText => String.Format(
7 | Strings.Installer_Welcome_MainText,
8 | "[github.com/bloxstraplabs/bloxstrap](https://github.com/bloxstraplabs/bloxstrap)",
9 | "[bloxstraplabs.com](https://bloxstraplabs.com)"
10 | );
11 |
12 | public string VersionNotice { get; private set; } = "";
13 |
14 | public bool CanContinue { get; set; } = false;
15 |
16 | public event EventHandler? CanContinueEvent;
17 |
18 | // called by codebehind on page load
19 | public async void DoChecks()
20 | {
21 | var releaseInfo = await App.GetLatestRelease();
22 |
23 | if (releaseInfo is not null)
24 | {
25 | if (Utilities.CompareVersions(App.Version, releaseInfo.TagName) == VersionComparison.LessThan)
26 | {
27 | VersionNotice = String.Format(Strings.Installer_Welcome_UpdateNotice, App.Version, releaseInfo.TagName.Replace("v", ""));
28 | OnPropertyChanged(nameof(VersionNotice));
29 | }
30 | }
31 |
32 | CanContinue = true;
33 | OnPropertyChanged(nameof(CanContinue));
34 |
35 | CanContinueEvent?.Invoke(this, new EventArgs());
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/NotifyPropertyChangedViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace Bloxstrap.UI.ViewModels
4 | {
5 | public class NotifyPropertyChangedViewModel : INotifyPropertyChanged
6 | {
7 | public event PropertyChangedEventHandler? PropertyChanged;
8 | public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Settings/BehaviourViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.UI.ViewModels.Settings
2 | {
3 | public class BehaviourViewModel : NotifyPropertyChangedViewModel
4 | {
5 | public bool ConfirmLaunches
6 | {
7 | get => App.Settings.Prop.ConfirmLaunches;
8 | set => App.Settings.Prop.ConfirmLaunches = value;
9 | }
10 |
11 | public bool ForceRobloxLanguage
12 | {
13 | get => App.Settings.Prop.ForceRobloxLanguage;
14 | set => App.Settings.Prop.ForceRobloxLanguage = value;
15 | }
16 |
17 | public bool BackgroundUpdates
18 | {
19 | get => App.Settings.Prop.BackgroundUpdatesEnabled;
20 | set => App.Settings.Prop.BackgroundUpdatesEnabled = value;
21 | }
22 |
23 | public bool IsRobloxInstallationMissing => String.IsNullOrEmpty(App.RobloxState.Prop.Player.VersionGuid) && String.IsNullOrEmpty(App.RobloxState.Prop.Studio.VersionGuid);
24 |
25 | public bool ForceRobloxReinstallation
26 | {
27 | get => App.State.Prop.ForceReinstall || IsRobloxInstallationMissing;
28 | set => App.State.Prop.ForceReinstall = value;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Settings/FastFlagEditorWarningViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 |
5 | using CommunityToolkit.Mvvm.Input;
6 | using Wpf.Ui.Mvvm.Contracts;
7 |
8 | using Bloxstrap.UI.Elements.Settings.Pages;
9 |
10 | namespace Bloxstrap.UI.ViewModels.Settings
11 | {
12 | internal class FastFlagEditorWarningViewModel : NotifyPropertyChangedViewModel
13 | {
14 | private Page _page;
15 |
16 | private CancellationTokenSource? _cancellationTokenSource;
17 |
18 | public string ContinueButtonText { get; set; } = "";
19 |
20 | public bool CanContinue { get; set; } = false;
21 |
22 | public ICommand GoBackCommand => new RelayCommand(GoBack);
23 |
24 | public ICommand ContinueCommand => new RelayCommand(Continue);
25 |
26 | public FastFlagEditorWarningViewModel(Page page)
27 | {
28 | _page = page;
29 | }
30 |
31 | public void StopCountdown()
32 | {
33 | _cancellationTokenSource?.Cancel();
34 | _cancellationTokenSource = null;
35 | }
36 |
37 | public void StartCountdown()
38 | {
39 | StopCountdown();
40 |
41 | _cancellationTokenSource = new CancellationTokenSource();
42 | DoCountdown(_cancellationTokenSource.Token);
43 | }
44 |
45 | private async void DoCountdown(CancellationToken token)
46 | {
47 | CanContinue = false;
48 | OnPropertyChanged(nameof(CanContinue));
49 |
50 | for (int i = 10; i > 0; i--)
51 | {
52 | ContinueButtonText = $"({i}) {Strings.Menu_FastFlagEditor_Warning_Continue}";
53 | OnPropertyChanged(nameof(ContinueButtonText));
54 |
55 | try
56 | {
57 | await Task.Delay(1000, token);
58 | }
59 | catch (TaskCanceledException)
60 | {
61 | return;
62 | }
63 | }
64 |
65 | ContinueButtonText = Strings.Menu_FastFlagEditor_Warning_Continue;
66 | OnPropertyChanged(nameof(ContinueButtonText));
67 |
68 | CanContinue = true;
69 | OnPropertyChanged(nameof(CanContinue));
70 | }
71 |
72 | private void Continue()
73 | {
74 | if (!CanContinue)
75 | return;
76 |
77 | App.State.Prop.ShowFFlagEditorWarning = false;
78 | App.State.Save(); // should we be force saving here?
79 |
80 | if (Window.GetWindow(_page) is INavigationWindow window)
81 | window.Navigate(typeof(FastFlagEditorPage));
82 | }
83 |
84 | private void GoBack()
85 | {
86 | if (Window.GetWindow(_page) is INavigationWindow window)
87 | window.Navigate(typeof(FastFlagsPage));
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Settings/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 | using Bloxstrap.UI.Elements.About;
4 | using CommunityToolkit.Mvvm.Input;
5 |
6 | namespace Bloxstrap.UI.ViewModels.Settings
7 | {
8 | public class MainWindowViewModel : NotifyPropertyChangedViewModel
9 | {
10 | public ICommand OpenAboutCommand => new RelayCommand(OpenAbout);
11 |
12 | public ICommand SaveSettingsCommand => new RelayCommand(SaveSettings);
13 |
14 | public ICommand CloseWindowCommand => new RelayCommand(CloseWindow);
15 |
16 | public EventHandler? RequestSaveNoticeEvent;
17 |
18 | public EventHandler? RequestCloseWindowEvent;
19 |
20 | public bool TestModeEnabled
21 | {
22 | get => App.LaunchSettings.TestModeFlag.Active;
23 | set
24 | {
25 | if (value)
26 | {
27 | var result = Frontend.ShowMessageBox(Strings.Menu_TestMode_Prompt, MessageBoxImage.Information, MessageBoxButton.YesNo);
28 |
29 | if (result != MessageBoxResult.Yes)
30 | return;
31 | }
32 |
33 | App.LaunchSettings.TestModeFlag.Active = value;
34 | }
35 | }
36 |
37 | private void OpenAbout() => new MainWindow().ShowDialog();
38 |
39 | private void CloseWindow() => RequestCloseWindowEvent?.Invoke(this, EventArgs.Empty);
40 |
41 | private void SaveSettings()
42 | {
43 | const string LOG_IDENT = "MainWindowViewModel::SaveSettings";
44 |
45 | App.Settings.Save();
46 | App.State.Save();
47 | App.FastFlags.Save();
48 |
49 | foreach (var pair in App.PendingSettingTasks)
50 | {
51 | var task = pair.Value;
52 |
53 | if (task.Changed)
54 | {
55 | App.Logger.WriteLine(LOG_IDENT, $"Executing pending task '{task}'");
56 | task.Execute();
57 | }
58 | }
59 |
60 | App.PendingSettingTasks.Clear();
61 |
62 | RequestSaveNoticeEvent?.Invoke(this, EventArgs.Empty);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Bloxstrap/UI/ViewModels/Settings/ShortcutsViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.UI.ViewModels.Settings
2 | {
3 | public class ShortcutsViewModel : NotifyPropertyChangedViewModel
4 | {
5 | public bool IsStudioOptionVisible => App.IsStudioVisible;
6 |
7 | public ShortcutTask DesktopIconTask { get; } = new("Desktop", Paths.Desktop, $"{App.ProjectName}.lnk");
8 |
9 | public ShortcutTask StartMenuIconTask { get; } = new("StartMenu", Paths.WindowsStartMenu, $"{App.ProjectName}.lnk");
10 |
11 | public ShortcutTask PlayerIconTask { get; } = new("RobloxPlayer", Paths.Desktop, $"{Strings.LaunchMenu_LaunchRoblox}.lnk", "-player");
12 |
13 | public ShortcutTask StudioIconTask { get; } = new("RobloxStudio", Paths.Desktop, $"{Strings.LaunchMenu_LaunchRobloxStudio}.lnk", "-studio");
14 |
15 | public ShortcutTask SettingsIconTask { get; } = new("Settings", Paths.Desktop, $"{Strings.Menu_Title}.lnk", "-settings");
16 |
17 | public ExtractIconsTask ExtractIconsTask { get; } = new();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Bloxstrap/Utility/Filesystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Xml.Linq;
7 |
8 | namespace Bloxstrap.Utility
9 | {
10 | internal static class Filesystem
11 | {
12 | internal static long GetFreeDiskSpace(string path)
13 | {
14 | foreach (var drive in DriveInfo.GetDrives())
15 | {
16 | // https://github.com/bloxstraplabs/bloxstrap/issues/1648#issuecomment-2192571030
17 | if (path.ToUpperInvariant().StartsWith(drive.Name))
18 | return drive.AvailableFreeSpace;
19 | }
20 |
21 | return -1;
22 | }
23 |
24 | internal static void AssertReadOnly(string filePath)
25 | {
26 | var fileInfo = new FileInfo(filePath);
27 |
28 | if (!fileInfo.Exists || !fileInfo.IsReadOnly)
29 | return;
30 |
31 | fileInfo.IsReadOnly = false;
32 | App.Logger.WriteLine("Filesystem::AssertReadOnly", $"The following file was set as read-only: {filePath}");
33 | }
34 |
35 | internal static void AssertReadOnlyDirectory(string directoryPath)
36 | {
37 | var directory = new DirectoryInfo(directoryPath) { Attributes = FileAttributes.Normal };
38 |
39 | foreach (var info in directory.GetFileSystemInfos("*", SearchOption.AllDirectories))
40 | info.Attributes = FileAttributes.Normal;
41 |
42 | App.Logger.WriteLine("Filesystem::AssertReadOnlyDirectory", $"The following directory was set as read-only: {directoryPath}");
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Bloxstrap/Utility/FixedCapacityList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Utility
8 | {
9 | internal class FixedSizeList : List
10 | {
11 | public int MaxSize { get; }
12 |
13 | public FixedSizeList(int size)
14 | {
15 | MaxSize = size;
16 | }
17 |
18 | public new void Add(T item)
19 | {
20 | if (Count >= MaxSize)
21 | RemoveAt(Count - 1);
22 | base.Add(item);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Bloxstrap/Utility/Http.cs:
--------------------------------------------------------------------------------
1 | namespace Bloxstrap.Utility
2 | {
3 | internal static class Http
4 | {
5 | ///
6 | /// Gets and deserializes a JSON API response to the specified object
7 | ///
8 | ///
9 | ///
10 | ///
11 | ///
12 | public static async Task GetJson(string url)
13 | {
14 | var request = await App.HttpClient.GetAsync(url);
15 |
16 | request.EnsureSuccessStatusCode();
17 |
18 | string json = await request.Content.ReadAsStringAsync();
19 |
20 | return JsonSerializer.Deserialize(json)!;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Bloxstrap/Utility/InterProcessLock.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Bloxstrap.Utility
8 | {
9 | public class InterProcessLock : IDisposable
10 | {
11 | public Mutex Mutex { get; private set; }
12 |
13 | public bool IsAcquired { get; private set; }
14 |
15 | public InterProcessLock(string name) : this(name, TimeSpan.Zero) { }
16 |
17 | public InterProcessLock(string name, TimeSpan timeout)
18 | {
19 | Mutex = new Mutex(false, "Bloxstrap-" + name);
20 |
21 | try
22 | {
23 | IsAcquired = Mutex.WaitOne(timeout);
24 | }
25 | catch (AbandonedMutexException)
26 | {
27 | IsAcquired = true;
28 | }
29 | }
30 |
31 | public void Dispose()
32 | {
33 | if (IsAcquired)
34 | {
35 | Mutex.ReleaseMutex();
36 | IsAcquired = false;
37 | }
38 |
39 | GC.SuppressFinalize(this);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Bloxstrap/Utility/MD5Hash.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 |
3 | namespace Bloxstrap.Utility
4 | {
5 | public static class MD5Hash
6 | {
7 | public static string FromBytes(byte[] data)
8 | {
9 | using MD5 md5 = MD5.Create();
10 | return Stringify(md5.ComputeHash(data));
11 | }
12 |
13 | public static string FromStream(Stream stream)
14 | {
15 | stream.Seek(0, SeekOrigin.Begin);
16 |
17 | using MD5 md5 = MD5.Create();
18 | return Stringify(md5.ComputeHash(stream));
19 | }
20 |
21 | public static string FromFile(string filename)
22 | {
23 | using MD5 md5 = MD5.Create();
24 | using FileStream stream = File.OpenRead(filename);
25 | return FromStream(stream);
26 | }
27 |
28 | public static string FromString(string str)
29 | {
30 | return FromBytes(Encoding.UTF8.GetBytes(str));
31 | }
32 |
33 | public static string Stringify(byte[] hash)
34 | {
35 | return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Bloxstrap/Utility/Shortcut.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using Bloxstrap.Resources;
3 |
4 | namespace Bloxstrap.Utility
5 | {
6 | internal static class Shortcut
7 | {
8 | private static GenericTriState _loadStatus = GenericTriState.Unknown;
9 |
10 | public static void Create(string exePath, string exeArgs, string lnkPath)
11 | {
12 | const string LOG_IDENT = "Shortcut::Create";
13 |
14 | if (File.Exists(lnkPath))
15 | return;
16 |
17 | try
18 | {
19 | ShellLink.Shortcut.CreateShortcut(exePath, exeArgs, exePath, 0).WriteToFile(lnkPath);
20 |
21 | if (_loadStatus != GenericTriState.Successful)
22 | _loadStatus = GenericTriState.Successful;
23 | }
24 | catch (FileNotFoundException ex)
25 | {
26 | App.Logger.WriteLine(LOG_IDENT, $"Failed to create a shortcut for {lnkPath}!");
27 | App.Logger.WriteException(LOG_IDENT, ex);
28 |
29 | if (_loadStatus == GenericTriState.Failed)
30 | return;
31 |
32 | _loadStatus = GenericTriState.Failed;
33 |
34 | Frontend.ShowMessageBox(Strings.Dialog_CannotCreateShortcuts, MessageBoxImage.Information);
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Images/Bloxstrap-full-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Images/Bloxstrap-full-dark.png
--------------------------------------------------------------------------------
/Images/Bloxstrap-full-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Images/Bloxstrap-full-light.png
--------------------------------------------------------------------------------
/Images/Bloxstrap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloxstraplabs/bloxstrap/1f21e8ce0b073e2684ce36564a6cc2cca1b01b04/Images/Bloxstrap.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 pizzaboxer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Scripts/Translations/find-unused.py:
--------------------------------------------------------------------------------
1 | import re, glob
2 |
3 | directory = input("Enter project path (the one containing Bloxstrap.csproj): ")
4 |
5 | existing = []
6 | found = []
7 |
8 | with open(f"{directory}\\Resources\\Strings.resx", "r") as file:
9 | existing = re.findall("name=\"([a-zA-Z0-9.]+)\" xml:space=\"preserve\"", file.read())
10 |
11 | for filename in glob.glob(f"{directory}\\**\\*.*", recursive=True):
12 | if "\\bin\\" in filename or "\\obj\\" in filename or "\\Resources\\" in filename:
13 | continue
14 |
15 | try:
16 | with open(filename, "r") as file:
17 | contents = file.read()
18 |
19 | matches = re.findall("Strings.([a-zA-Z0-9_]+)", contents)
20 | for match in matches:
21 | if not '_' in match:
22 | continue
23 |
24 | ref = match.replace('_', '.')
25 | if not ref in found:
26 | found.append(ref)
27 |
28 | matches = re.findall("FromTranslation = \"([a-zA-Z0-9.]+)\"", contents)
29 | for match in matches:
30 | if not match in found:
31 | found.append(match)
32 |
33 | except Exception:
34 | print(f"Could not open {filename}")
35 | continue
36 |
37 | for entry in existing:
38 | if not entry in found and not "Enums." in entry:
39 | print(entry)
--------------------------------------------------------------------------------
/Scripts/Translations/prep.py:
--------------------------------------------------------------------------------
1 | import glob, shutil, re
2 |
3 | exports = input("Path of folder of exported Crowdin files: ")
4 | dest = input("Destination resources folder: ")
5 |
6 | for filename in glob.glob(f"{exports}\\**\\*.*", recursive=True):
7 | print(f"Copying {filename}")
8 |
9 | localeCode = re.search("\\\\([a-zA-Z\\-]+)\\\\Strings.", filename).group(1)
10 |
11 | shutil.copy(filename, dest + f"\\Strings.{localeCode}.resx")
--------------------------------------------------------------------------------