44 Commits

Author SHA1 Message Date
Frog 028dd1586b Increment Application Version
- Increment app version to 5.0.1.7
2026-01-18 13:04:40 -08:00
Frog f5d6007404 Sory By Name By Default
- Adjusts the Sort By Name setting to be enabled by default for a more user friendly experience.
2026-01-18 13:02:44 -08:00
Frog 1c7ffb215d BugFix for DLC Query Failure - Fixes #5
- Fixes #5 Corrects null pointer failure. This ensures publishers exist AND that it contains at least one object before we access it.
2026-01-18 12:47:03 -08:00
Frog 1bd5501869 Update SmokeAPI to v4.1.3
- Updated SmokeAPI to v4.1.3
- Included MD5 hash for older versions (V4.1.0, V4.1.1, v4.1.2)
2026-01-18 12:33:25 -08:00
Frog 1db70541f9 Increment App Version 2025-11-21 03:01:44 -08:00
Frog ae08e990cc Enable Dark Mode by Default
- Enabled dark mode by default (Looks decent enough)
2025-11-21 02:52:01 -08:00
Frog 12c7c9a9d2 Change Dark Mode Toggle to Checkbox
- Changed dark mode toggle to Checkbox instead of button > better aligns with other settings in the top panel. (Gee, sure is getting crowded up there)
2025-11-21 02:48:19 -08:00
Frog 701ca5627d Merge branch 'main' of https://github.com/FroggMaster/CreamInstaller 2025-11-21 02:19:40 -08:00
Frog c0af3b85bb Dark Mode / Hyperlink Color Fix
- Fixes hard to read hyperlinks in Dark Mode
2025-11-21 02:19:18 -08:00
Frog 8577e6df7f Update README.md
- Correct typo/extra word.
2025-11-20 23:03:26 -08:00
Frog 961b7153f4 Added Info about CI Builds to ReadMe / Added Status Badge for CI Builds / Added Status Badge for Latest Release
-  Added Info about CI Builds to ReadMe 
- Added Status Badge for CI Builds 
- Added Status Badge for Latest Release
2025-11-20 02:55:35 -08:00
Frog e640b8b15d Dark mode WIP
- The start of a dark mode theme
- Adds a button to toggle dark mode in the top options panel. (The buttons kind of ugly though and I may change this to a checkbox to align with the other existing options)
- Added library uxtheme.dll for handling scrollbar themeing (Dealing with scrollbars sucks)
- Added ThemeManager for handling of theme colors (Allows for potential expandability I'll probably never implement)
2025-11-20 02:35:51 -08:00
Frog bcf3ff84fe Merge branch 'main' of https://github.com/FroggMaster/CreamInstaller 2025-11-19 22:58:40 -08:00
Frog eb1fee38f3 Slight cleaner preview image, that also shows an enabled proxy dll. 2025-11-19 22:58:25 -08:00
Frog cffc4cce07 Update ci-builds.yml
Bug Fix: I forgot to adjust the Rename-Item PS command to rename the EXE before packaging.
2025-11-19 22:04:24 -08:00
Frog b7a9505599 Adjusted CI Build Workflow
- Adjusted artifact name to include CI-Release
- Adjusted EXE to include CI
2025-11-19 03:36:36 -08:00
Frog 094d60b003 Merge branch 'main' of https://github.com/FroggMaster/CreamInstaller 2025-11-19 03:32:11 -08:00
Frog 09cafa27fb Update ci-builds.yml
- Fix artifact becoming two ZIPs (LOL woops)
2025-11-19 03:30:34 -08:00
Frog e6fa7b4a39 Fixed unreachable logging segment for CreamAPI
- Fixed unreachable code that provides information about deleted config file
- Adjusted old comment from pointfeev that indiciated SmokeAPI might always be false (it's now toggleable)
2025-11-19 03:27:28 -08:00
Frog 8a24bdad81 Update ci-builds.yml
- GH Action fix
2025-11-19 03:17:26 -08:00
Frog 21bcfae688 Update README.md
- Minor change to ReadMe changing "extract" to "move"
2025-11-19 03:15:02 -08:00
Frog 4063e482dd Add zip release
- Add zip release for internal application updates
- Left the EXE for ease of access for those that don't want to extract a ZIP on first install.
2025-11-19 03:00:47 -08:00
Frog bdb1d9ffd2 Update ci-builds.yml
- Fix to include git commit in final CI build
2025-11-19 02:59:44 -08:00
Frog 800cb2b9f6 Rename CI-Builds / Adjust so CI Builds include commit in ZIP file
- Updated name of CI builds for clarity to include -
- Updated so the final ZIP file includes the commit it was built from
- Adjusted artifact release name.
2025-11-19 02:53:29 -08:00
Frog 8b6013e1c0 Update and rename autobuild.yml to cibuilds.yml
- Adjusted old AutoBuild script for CI builds
- Renamed from AutoBuild to CIBuilds
- Configured to run on every commit to main branch
2025-11-19 02:22:53 -08:00
Frog 668f367838 Update preview image 2025-11-19 02:16:32 -08:00
Frog 6613b777a7 Increment App version / Adjust Copyright Info
- Increment App Version
- Adjust Copyright Info / Repository
2025-11-19 02:01:17 -08:00
Frog 1036f8a8b4 Apply SelectForm.cs from commit 6fa5503 2025-11-18 02:03:11 -08:00
Frog c5a3a98827 Update README.md
- Adjusted ReadMe instructions to reflect EXE download rather than ZIP
- Updated link to Issue 40 > Now points to Web Archived version of the original issue before being hit by DCMA
2025-11-18 01:51:03 -08:00
Frog 4751a3bf76 Update README.md
- Fixed ReadMe change from previous merge (I really should pay a little more attention when pulling from a fork, I guess that's what I get for doing things at 2AM)
2025-11-18 01:42:44 -08:00
Frog de43eb9561 Increment application version
- Increment application version to 5.0.1.4
2025-11-14 00:51:40 -08:00
Frog 6931e43874 Adjusted Desinger So it Loads DPI Unaware / Fixed Options Panel UI
- This should avoid the UI from cutting off on larger DPI systems.
2025-11-14 00:51:05 -08:00
Frog 8958c0626f Correct Repo Name Again / Adjust hard to understand help text for SmokeAPI
- Corrected Repository owner name again, missed this during the merge (Unintended change pointing to the wrong repository)
- Adjusted some hard to understand text about the experimental warning for SmokeAPI usage
2025-11-14 00:02:19 -08:00
Frog 63d6879465 Update create-release.yml 2025-11-13 23:20:22 -08:00
Frog 14d71b1746 Add GitHub Actions workflow for creating releases
- Add GitHub Actions workflow for creating releases
2025-11-13 23:16:22 -08:00
Frog 7bf5276109 Merge branch 'main' of https://github.com/HvTcCore/CreamInstaller 2025-11-13 23:04:16 -08:00
Frog 637015a509 Merge branch 'main' of https://github.com/FroggMaster/CreamInstaller 2025-11-13 23:02:41 -08:00
Frog b45b5c6570 Changed the repository owner defined in the code 2025-11-13 23:02:09 -08:00
Soul Shard 27ebdd8331 Fix EpicGames detect, possible fix stuck on Steam detect
Fixed broken DLC detection for games from Epic Games. Probably fixed detection freezing on Steam games that are unavailable in certain regions.
2025-11-14 10:30:34 +07:00
Soul Shard 3f910b9d07 Update SmokeAPI and config generation
SmokeAPI updated to v4.0.0, configs now generating always
2025-11-12 03:30:26 +07:00
Soul Shard c8a65f35bf Update to latest util versions, restore SmokeAPI
Utilities have been updated to the latest versions. The ability to use SmokeAPI instead of CreamAPI has been restored, and a checkbox has been added to switch between them.
2025-10-01 06:07:54 +07:00
Frog 12e9a4b66f Update README.md
- Fixed preview screenshot
2025-02-23 23:42:53 -08:00
Frog 0d6243956d Update README.md
- Adjusted old links to point to this repository.
2025-02-23 23:40:58 -08:00
Frog 8d5e2487d4 Update Program.cs
- Changed defined value for variable RepositoryOwner to FroggMaster from pointfeev
2024-11-16 08:21:26 -08:00
78 changed files with 886 additions and 201 deletions
+47
View File
@@ -0,0 +1,47 @@
name: CI Builds
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore dependencies
run: dotnet restore CreamInstaller.sln
- name: Build Release
run: dotnet build CreamInstaller.sln --configuration Release --no-restore
- name: Publish single-file
run: dotnet publish CreamInstaller.sln -c Release -r win-x64 -p:PublishSingleFile=true --self-contained true --output ./publish
- name: Set short commit SHA
id: vars
run: |
$shortSha = $env:GITHUB_SHA.Substring(0,7)
Write-Output "shortSha=$shortSha" >> $env:GITHUB_ENV
shell: pwsh
- name: Rename EXE with short commit SHA
run: |
Rename-Item -Path ./publish/CreamInstaller.exe -NewName "CreamInstaller-CI-$env:shortSha.exe"
shell: pwsh
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: CreamInstaller-CI-Release-${{ env.shortSha }}
path: ./publish/CreamInstaller-CI-${{ env.shortSha }}.exe
+69
View File
@@ -0,0 +1,69 @@
name: Create Release
on:
workflow_dispatch:
inputs:
version:
description: "Version number (example: 5.0.1.3)"
required: true
type: string
title:
description: "Release title (optional)"
required: false
type: string
notes:
description: "Release notes (optional)"
required: false
type: string
jobs:
release:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Needed for tag creation and pushing
- name: Create and push tag
shell: pwsh
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
$tag = "v${{ inputs.version }}"
Write-Host "Creating tag $tag"
git tag $tag
git push origin $tag
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore dependencies
run: dotnet restore CreamInstaller.sln
- name: Build Release
run: dotnet build CreamInstaller.sln --configuration Release --no-restore
- name: Publish single-file
run: dotnet publish CreamInstaller.sln -c Release -r win-x64 -p:PublishSingleFile=true --self-contained true --output ./publish
- name: Zip Release
run: |
Compress-Archive -Path ./publish/* -DestinationPath ./publish/CreamInstaller.zip
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ inputs.version }}
name: ${{ inputs.title || format('Release v{0}', inputs.version) }}
body: ${{ inputs.notes }}
files: |
./publish/CreamInstaller.exe
./publish/CreamInstaller.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+13 -1
View File
@@ -42,6 +42,18 @@ internal class CustomForm : Form
}
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
ThemeManager.Apply(this); // apply current theme (initial or toggled)
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
ThemeManager.Apply(this); // ensure late-added controls also themed
}
private void OnHelpButtonClicked(object sender, EventArgs args)
{
using DialogForm helpDialog = new(this);
@@ -52,7 +64,7 @@ internal class CustomForm : Form
"Automatically finds all installed Steam, Epic and Ubisoft games with their respective DLC-related DLL locations on the user's computer,\n"
+ "parses SteamCMD, Steam Store and Epic Games Store for user-selected games' DLCs, then provides a very simple graphical interface\n"
+ "utilizing the gathered information for the maintenance of DLC unlockers.\n\n"
+ $"The program utilizes the latest version of [CreamAPI](https://cs.rin.ru/forum/viewtopic.php?f=29&t=70576) by [deadmau5](https://cs.rin.ru/forum/viewtopic.php?f=29&t=70576). It also utilizes the latest versions of [Koaloader]({acidicoala}/Koaloader), [ScreamAPI]({acidicoala}/ScreamAPI), [Uplay R1\n"
+ $"The program utilizes the latest version of [CreamAPI](https://cs.rin.ru/forum/viewtopic.php?f=29&t=70576) by [deadmau5](https://cs.rin.ru/forum/viewtopic.php?f=29&t=70576). It also utilizes the latest versions of [SmokeAPI]({acidicoala}/SmokeAPI), [Koaloader]({acidicoala}/Koaloader), [ScreamAPI]({acidicoala}/ScreamAPI), [Uplay R1\n"
+ $"Unlocker]({acidicoala}/UplayR1Unlocker) and [Uplay R2 Unlocker]({acidicoala}/UplayR2Unlocker), all by [acidicoala]({acidicoala}). All unlockers are downloaded and embedded into the program itself; no further\n"
+ "downloads necessary on your part!\n\n"
+ "USAGE:\n" + " 1. Choose which programs and/or games the program should scan for DLC.\n"
@@ -22,7 +22,7 @@ internal sealed class StringComparer : IComparer<string>
{
public int Compare(string a, string b)
=> !int.TryParse(a, out _) && !int.TryParse(b, out _)
? string.Compare(a, b, StringComparison.CurrentCulture)
? string.Compare(a, b, StringComparison.Ordinal)
: !int.TryParse(a, out int A)
? 1
: !int.TryParse(b, out int B)
+4 -3
View File
@@ -4,8 +4,8 @@
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\program.ico</ApplicationIcon>
<Version>5.0.1.0</Version>
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
<Version>5.0.1.7</Version>
<Copyright>2025, FroggMaster (https://github.com/FroggMaster)</Copyright>
<Company>CreamInstaller</Company>
<Product>Automatic DLC Unlocker Installer &amp; Configuration Generator</Product>
<StartupObject>CreamInstaller.Program</StartupObject>
@@ -24,6 +24,7 @@
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
<Platforms>x64</Platforms>
<ForceDesignerDpiUnaware>true</ForceDesignerDpiUnaware>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<AssemblyName>$(Company)</AssemblyName>
@@ -207,4 +208,4 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>
+74 -25
View File
@@ -68,6 +68,9 @@ internal sealed partial class InstallForm : CustomForm
bool useCreamApiProxy = selection.UseProxy && !Program.UseSmokeAPI &&
(selection.Platform is Platform.Steam || selection.Platform is Platform.Paradox &&
selection.ExtraSelections.Any(s => s.Platform is Platform.Steam));
bool useSmokeApiProxy = selection.UseProxy && Program.UseSmokeAPI &&
(selection.Platform is Platform.Steam || selection.Platform is Platform.Paradox &&
selection.ExtraSelections.Any(s => s.Platform is Platform.Steam));
UpdateUser(
$"{(uninstalling ? "Uninstalling" : "Installing")}" + $" {(uninstalling ? "from" : "for")} " +
@@ -84,7 +87,7 @@ internal sealed partial class InstallForm : CustomForm
if (Program.Canceled)
return;
directory.GetKoaloaderComponents(out string old_config, out string config);
directory.GetKoaloaderComponents(out string old_config, out string config, out _);
if (directory.GetKoaloaderProxies().Any(proxy =>
proxy.FileExists() && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|| directory != selection.RootDirectory &&
@@ -97,19 +100,36 @@ internal sealed partial class InstallForm : CustomForm
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
}
directory.GetCreamApiComponents(out _, out _, out _, out _, out config);
if (directory.GetCreamApiProxies().Any(proxy =>
proxy.FileExists() && (proxy.IsResourceFile(ResourceIdentifier.Steamworks32) ||
proxy.IsResourceFile(ResourceIdentifier.Steamworks64))))
if (!Program.UseSmokeAPI)
{
UpdateUser(
"Uninstalling CreamAPI in proxy mode from " + selection.Name +
$" in incorrect directory \"{directory}\" . . . ", LogTextBox.Operation);
await CreamAPI.ProxyUninstall(directory, this);
directory.GetCreamApiComponents(out _, out _, out _, out _, out config);
if (directory.GetCreamApiProxies().Any(proxy =>
proxy.FileExists() && (proxy.IsResourceFile(ResourceIdentifier.Steamworks32) ||
proxy.IsResourceFile(ResourceIdentifier.Steamworks64))))
{
UpdateUser(
"Uninstalling CreamAPI in proxy mode from " + selection.Name +
$" in incorrect directory \"{directory}\" . . . ", LogTextBox.Operation);
await CreamAPI.ProxyUninstall(directory, this);
}
}
else
{
directory.GetSmokeApiComponents(out _, out _, out _, out _, out old_config, out config, out _,
out _, out _);
if (directory.GetSmokeApiProxies().Any(proxy =>
proxy.FileExists() && (proxy.IsResourceFile(ResourceIdentifier.Steamworks32) ||
proxy.IsResourceFile(ResourceIdentifier.Steamworks64))))
{
UpdateUser(
"Uninstalling SmokeAPI in proxy mode from " + selection.Name +
$" in incorrect directory \"{directory}\" . . . ", LogTextBox.Operation);
await SmokeAPI.ProxyUninstall(directory, this);
}
}
}
if (uninstalling || !useKoaloader || !useCreamApiProxy)
if (uninstalling || !useKoaloader || !useCreamApiProxy || !useSmokeApiProxy)
foreach ((string directory, _) in selection.ExecutableDirectories)
{
if (Program.Canceled)
@@ -117,7 +137,7 @@ internal sealed partial class InstallForm : CustomForm
if (uninstalling || !useKoaloader)
{
directory.GetKoaloaderComponents(out string old_config, out string config);
directory.GetKoaloaderComponents(out string old_config, out string config, out _);
if (directory.GetKoaloaderProxies().Any(proxy =>
proxy.FileExists() && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|| Koaloader.AutoLoadDLLs.Any(pair => (directory + @"\" + pair.dll).FileExists()) ||
@@ -130,23 +150,44 @@ internal sealed partial class InstallForm : CustomForm
}
}
if (uninstalling || !useCreamApiProxy)
if (!Program.UseSmokeAPI)
{
directory.GetCreamApiComponents(out _, out _, out _, out _, out string config);
if (directory.GetCreamApiProxies().Any(proxy =>
proxy.FileExists() && (proxy.IsResourceFile(ResourceIdentifier.Steamworks32) ||
proxy.IsResourceFile(ResourceIdentifier.Steamworks64))) ||
config.FileExists())
if (uninstalling || !useCreamApiProxy)
{
UpdateUser(
"Uninstalling CreamAPI in proxy mode from " + selection.Name +
$" in directory \"{directory}\" . . . ", LogTextBox.Operation);
await CreamAPI.ProxyUninstall(directory, this);
directory.GetCreamApiComponents(out _, out _, out _, out _, out string config);
if (directory.GetCreamApiProxies().Any(proxy =>
proxy.FileExists() && (proxy.IsResourceFile(ResourceIdentifier.Steamworks32) ||
proxy.IsResourceFile(ResourceIdentifier.Steamworks64))) ||
config.FileExists())
{
UpdateUser(
"Uninstalling CreamAPI in proxy mode from " + selection.Name +
$" in directory \"{directory}\" . . . ", LogTextBox.Operation);
await CreamAPI.ProxyUninstall(directory, this);
}
}
}
else
{
if (uninstalling || !useSmokeApiProxy)
{
directory.GetSmokeApiComponents(out _, out _, out _, out _, out string old_config, out string config, out _,
out _, out _);
if (directory.GetSmokeApiProxies().Any(proxy =>
proxy.FileExists() && (proxy.IsResourceFile(ResourceIdentifier.Steamworks32) ||
proxy.IsResourceFile(ResourceIdentifier.Steamworks64))) ||
config.FileExists())
{
UpdateUser(
"Uninstalling SmokeAPI in proxy mode from " + selection.Name +
$" in directory \"{directory}\" . . . ", LogTextBox.Operation);
await SmokeAPI.ProxyUninstall(directory, this);
}
}
}
}
bool uninstallingForProxy = uninstalling || useKoaloader || useCreamApiProxy;
bool uninstallingForProxy = uninstalling || useKoaloader || useCreamApiProxy || useSmokeApiProxy;
int count = selection.DllDirectories.Count, cur = 0;
foreach (string directory in selection.DllDirectories)
{
@@ -199,7 +240,7 @@ internal sealed partial class InstallForm : CustomForm
if (selection.Platform is Platform.Epic or Platform.Paradox)
{
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string config, out string log);
out string api64_o, out string old_config, out string config, out string old_log, out string log);
if (uninstallingForProxy
? api32_o.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists()
: api32.FileExists() || api64.FileExists())
@@ -253,13 +294,13 @@ internal sealed partial class InstallForm : CustomForm
UpdateProgress(++cur / count * 100);
}
if ((useCreamApiProxy || useKoaloader) && !uninstalling)
if ((useCreamApiProxy || useSmokeApiProxy || useKoaloader) && !uninstalling)
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
{
if (Program.Canceled)
return;
if (useCreamApiProxy)
if (useCreamApiProxy && !Program.UseSmokeAPI)
{
UpdateUser(
"Installing CreamAPI in proxy mode for " + selection.Name +
@@ -267,6 +308,14 @@ internal sealed partial class InstallForm : CustomForm
LogTextBox.Operation);
await CreamAPI.ProxyInstall(directory, binaryType, selection, this);
}
else if (useSmokeApiProxy && Program.UseSmokeAPI)
{
UpdateUser(
"Installing SmokeAPI in proxy mode for " + selection.Name +
$" in directory \"{directory}\" . . . ",
LogTextBox.Operation);
await SmokeAPI.ProxyInstall(directory, binaryType, selection, this);
}
else if (useKoaloader)
{
UpdateUser("Installing Koaloader for " + selection.Name + $" in directory \"{directory}\" . . . ",
+1
View File
@@ -106,6 +106,7 @@ namespace CreamInstaller.Forms
//
sortCheckBox.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
sortCheckBox.AutoSize = true;
sortCheckBox.Checked = true; // Enable Sort By Name by default
sortCheckBox.Location = new System.Drawing.Point(220, 247);
sortCheckBox.Margin = new Padding(3, 0, 0, 0);
sortCheckBox.Name = "sortCheckBox";
+1 -1
View File
@@ -14,7 +14,7 @@ internal sealed partial class SelectDialogForm : CustomForm
internal SelectDialogForm(IWin32Window owner) : base(owner)
{
InitializeComponent();
selectionTreeView.TreeViewNodeSorter = PlatformIdComparer.NodeName;
selectionTreeView.TreeViewNodeSorter = sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
}
internal DialogResult QueryUser(string groupBoxText,
+121 -23
View File
@@ -1,8 +1,8 @@
using System.ComponentModel;
using CreamInstaller.Components;
using CreamInstaller.Resources;
using System.ComponentModel;
using System.Windows.Forms;
using CreamInstaller.Components;
namespace CreamInstaller.Forms
{
partial class SelectForm
@@ -28,6 +28,11 @@ namespace CreamInstaller.Forms
blockedGamesFlowPanel = new FlowLayoutPanel();
blockedGamesCheckBox = new CheckBox();
blockProtectedHelpButton = new Button();
useSmokeAPILayoutPanel = new FlowLayoutPanel();
useSmokeAPICheckBox = new CheckBox();
useSmokeAPIHelpButton = new Button();
darkModeFlowPanel = new FlowLayoutPanel();
darkModeCheckBox = new CheckBox();
allCheckBoxLayoutPanel = new FlowLayoutPanel();
allCheckBox = new CheckBox();
progressBar = new ProgressBar();
@@ -42,9 +47,12 @@ namespace CreamInstaller.Forms
resetButton = new Button();
saveFlowPanel = new FlowLayoutPanel();
selectionTreeView = new CustomTreeView();
topOptionsTable = new TableLayoutPanel();
programsGroupBox.SuspendLayout();
proxyFlowPanel.SuspendLayout();
blockedGamesFlowPanel.SuspendLayout();
useSmokeAPILayoutPanel.SuspendLayout();
darkModeFlowPanel.SuspendLayout();
allCheckBoxLayoutPanel.SuspendLayout();
saveFlowPanel.SuspendLayout();
SuspendLayout();
@@ -81,25 +89,20 @@ namespace CreamInstaller.Forms
// programsGroupBox
//
programsGroupBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
programsGroupBox.Controls.Add(proxyFlowPanel);
programsGroupBox.Controls.Add(noneFoundLabel);
programsGroupBox.Controls.Add(blockedGamesFlowPanel);
programsGroupBox.Controls.Add(allCheckBoxLayoutPanel);
programsGroupBox.Controls.Add(selectionTreeView);
programsGroupBox.Location = new System.Drawing.Point(12, 12);
programsGroupBox.Location = new System.Drawing.Point(12, 47);
programsGroupBox.Name = "programsGroupBox";
programsGroupBox.Size = new System.Drawing.Size(610, 287);
programsGroupBox.Size = new System.Drawing.Size(610, 252);
programsGroupBox.TabIndex = 8;
programsGroupBox.TabStop = false;
programsGroupBox.Text = "Programs / Games";
//
// proxyFlowPanel
//
proxyFlowPanel.Anchor = AnchorStyles.Top | AnchorStyles.Right;
proxyFlowPanel.AutoSize = true;
proxyFlowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
proxyFlowPanel.Controls.Add(proxyAllCheckBox);
proxyFlowPanel.Location = new System.Drawing.Point(478, -1);
proxyFlowPanel.Margin = new Padding(0);
proxyFlowPanel.Name = "proxyFlowPanel";
proxyFlowPanel.Size = new System.Drawing.Size(75, 19);
@@ -108,7 +111,6 @@ namespace CreamInstaller.Forms
//
// proxyAllCheckBox
//
proxyAllCheckBox.Anchor = AnchorStyles.Top | AnchorStyles.Right;
proxyAllCheckBox.AutoSize = true;
proxyAllCheckBox.Enabled = false;
proxyAllCheckBox.Location = new System.Drawing.Point(2, 0);
@@ -124,7 +126,7 @@ namespace CreamInstaller.Forms
noneFoundLabel.Dock = DockStyle.Fill;
noneFoundLabel.Location = new System.Drawing.Point(3, 19);
noneFoundLabel.Name = "noneFoundLabel";
noneFoundLabel.Size = new System.Drawing.Size(604, 265);
noneFoundLabel.Size = new System.Drawing.Size(604, 230);
noneFoundLabel.TabIndex = 1002;
noneFoundLabel.Text = "No applicable programs nor games were found on your computer!";
noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
@@ -132,12 +134,10 @@ namespace CreamInstaller.Forms
//
// blockedGamesFlowPanel
//
blockedGamesFlowPanel.Anchor = AnchorStyles.Top;
blockedGamesFlowPanel.AutoSize = true;
blockedGamesFlowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
blockedGamesFlowPanel.Controls.Add(blockedGamesCheckBox);
blockedGamesFlowPanel.Controls.Add(blockProtectedHelpButton);
blockedGamesFlowPanel.Location = new System.Drawing.Point(150, -1);
blockedGamesFlowPanel.Margin = new Padding(0);
blockedGamesFlowPanel.Name = "blockedGamesFlowPanel";
blockedGamesFlowPanel.Size = new System.Drawing.Size(170, 19);
@@ -172,22 +172,83 @@ namespace CreamInstaller.Forms
blockProtectedHelpButton.UseVisualStyleBackColor = true;
blockProtectedHelpButton.Click += OnBlockProtectedGamesHelpButtonClicked;
//
// useSmokeAPILayoutPanel
//
useSmokeAPILayoutPanel.AutoSize = true;
useSmokeAPILayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
useSmokeAPILayoutPanel.Controls.Add(useSmokeAPICheckBox);
useSmokeAPILayoutPanel.Controls.Add(useSmokeAPIHelpButton);
useSmokeAPILayoutPanel.Margin = new Padding(12, 0, 0, 0);
useSmokeAPILayoutPanel.Name = "useSmokeAPILayoutPanel";
useSmokeAPILayoutPanel.Size = new System.Drawing.Size(124, 19);
useSmokeAPILayoutPanel.TabIndex = 1006;
useSmokeAPILayoutPanel.WrapContents = false;
//
// useSmokeAPICheckBox
//
useSmokeAPICheckBox.AutoSize = true;
useSmokeAPICheckBox.Checked = true;
useSmokeAPICheckBox.CheckState = CheckState.Checked;
useSmokeAPICheckBox.Enabled = false;
useSmokeAPICheckBox.Location = new System.Drawing.Point(2, 0);
useSmokeAPICheckBox.Margin = new Padding(2, 0, 0, 0);
useSmokeAPICheckBox.Name = "useSmokeAPICheckBox";
useSmokeAPICheckBox.Size = new System.Drawing.Size(102, 19);
useSmokeAPICheckBox.TabIndex = 1;
useSmokeAPICheckBox.Text = "Use SmokeAPI";
useSmokeAPICheckBox.UseVisualStyleBackColor = true;
useSmokeAPICheckBox.CheckedChanged += OnUseSmokeAPICheckBoxChanged;
//
// useSmokeAPIHelpButton
//
useSmokeAPIHelpButton.Enabled = false;
useSmokeAPIHelpButton.Font = new System.Drawing.Font("Segoe UI", 7F);
useSmokeAPIHelpButton.Location = new System.Drawing.Point(104, 0);
useSmokeAPIHelpButton.Margin = new Padding(0, 0, 1, 0);
useSmokeAPIHelpButton.Name = "useSmokeAPIHelpButton";
useSmokeAPIHelpButton.Size = new System.Drawing.Size(19, 19);
useSmokeAPIHelpButton.TabIndex = 2;
useSmokeAPIHelpButton.Text = "?";
useSmokeAPIHelpButton.UseVisualStyleBackColor = true;
useSmokeAPIHelpButton.Click += OnUseSmokeAPIHelpButtonClicked;
//
// darkModeFlowPanel
//
darkModeFlowPanel.AutoSize = true;
darkModeFlowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
darkModeFlowPanel.Margin = new Padding(12, 0, 0, 0);
darkModeFlowPanel.Name = "darkModeFlowPanel";
darkModeFlowPanel.Size = new System.Drawing.Size(98, 19);
darkModeFlowPanel.TabIndex = 10011;
darkModeFlowPanel.WrapContents = false;
//
// darkModeCheckBox
//
darkModeCheckBox.AutoSize = true;
darkModeCheckBox.Enabled = true;
darkModeCheckBox.Location = new System.Drawing.Point(2, 0);
darkModeCheckBox.Margin = new Padding(2, 0, 0, 0);
darkModeCheckBox.Name = "darkModeCheckBox";
darkModeCheckBox.Size = new System.Drawing.Size(96, 19);
darkModeCheckBox.TabIndex = 1;
darkModeCheckBox.Text = "Enable Dark Mode";
darkModeCheckBox.UseVisualStyleBackColor = true;
darkModeCheckBox.CheckedChanged += OnDarkModeCheckBoxChanged;
darkModeFlowPanel.Controls.Add(darkModeCheckBox);
//
// allCheckBoxLayoutPanel
//
allCheckBoxLayoutPanel.Anchor = AnchorStyles.Top | AnchorStyles.Right;
allCheckBoxLayoutPanel.AutoSize = true;
allCheckBoxLayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
allCheckBoxLayoutPanel.Controls.Add(allCheckBox);
allCheckBoxLayoutPanel.Location = new System.Drawing.Point(562, -1);
allCheckBoxLayoutPanel.Margin = new Padding(0);
allCheckBoxLayoutPanel.Margin = new Padding(12, 0, 0, 0);
allCheckBoxLayoutPanel.Name = "allCheckBoxLayoutPanel";
allCheckBoxLayoutPanel.Size = new System.Drawing.Size(42, 19);
allCheckBoxLayoutPanel.TabIndex = 1006;
allCheckBoxLayoutPanel.TabIndex = 1007;
allCheckBoxLayoutPanel.WrapContents = false;
//
// allCheckBox
//
allCheckBox.Anchor = AnchorStyles.Top | AnchorStyles.Right;
allCheckBox.AutoSize = true;
allCheckBox.Checked = true;
allCheckBox.CheckState = CheckState.Checked;
@@ -211,7 +272,7 @@ namespace CreamInstaller.Forms
selectionTreeView.FullRowSelect = true;
selectionTreeView.Location = new System.Drawing.Point(3, 19);
selectionTreeView.Name = "selectionTreeView";
selectionTreeView.Size = new System.Drawing.Size(604, 265);
selectionTreeView.Size = new System.Drawing.Size(604, 230);
selectionTreeView.TabIndex = 1001;
//
// progressBar
@@ -285,6 +346,7 @@ namespace CreamInstaller.Forms
//
sortCheckBox.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
sortCheckBox.AutoSize = true;
sortCheckBox.Checked = true; // Enable Sort By Name by default
sortCheckBox.Location = new System.Drawing.Point(84, 380);
sortCheckBox.Margin = new Padding(3, 0, 0, 0);
sortCheckBox.Name = "sortCheckBox";
@@ -352,12 +414,39 @@ namespace CreamInstaller.Forms
saveFlowPanel.TabIndex = 10008;
saveFlowPanel.WrapContents = false;
//
// topOptionsTable
//
topOptionsTable.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
topOptionsTable.AutoSize = true;
topOptionsTable.AutoSizeMode = AutoSizeMode.GrowAndShrink;
topOptionsTable.ColumnCount = 6;
topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); // spacer
topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
topOptionsTable.Location = new System.Drawing.Point(12, 12);
topOptionsTable.Margin = new Padding(0);
topOptionsTable.Name = "topOptionsTable";
topOptionsTable.RowCount = 1;
topOptionsTable.RowStyles.Add(new RowStyle(SizeType.AutoSize));
topOptionsTable.Size = new System.Drawing.Size(610, 25);
topOptionsTable.TabIndex = 10009;
topOptionsTable.Controls.Clear();
topOptionsTable.Controls.Add(blockedGamesFlowPanel, 0, 0);
topOptionsTable.Controls.Add(useSmokeAPILayoutPanel, 1, 0);
topOptionsTable.Controls.Add(darkModeFlowPanel, 2, 0);
topOptionsTable.Controls.Add(proxyFlowPanel, 4, 0);
topOptionsTable.Controls.Add(allCheckBoxLayoutPanel, 5, 0);
//
// SelectForm
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
AutoScaleMode = AutoScaleMode.Dpi;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
ClientSize = new System.Drawing.Size(634, 411);
Controls.Add(topOptionsTable);
Controls.Add(saveFlowPanel);
Controls.Add(sortCheckBox);
Controls.Add(progressLabelDLCs);
@@ -378,11 +467,14 @@ namespace CreamInstaller.Forms
Text = "SelectForm";
Load += OnLoad;
programsGroupBox.ResumeLayout(false);
programsGroupBox.PerformLayout();
proxyFlowPanel.ResumeLayout(false);
proxyFlowPanel.PerformLayout();
blockedGamesFlowPanel.ResumeLayout(false);
blockedGamesFlowPanel.PerformLayout();
useSmokeAPILayoutPanel.ResumeLayout(false);
useSmokeAPILayoutPanel.PerformLayout();
darkModeFlowPanel.ResumeLayout(false);
darkModeFlowPanel.PerformLayout();
allCheckBoxLayoutPanel.ResumeLayout(false);
allCheckBoxLayoutPanel.PerformLayout();
saveFlowPanel.ResumeLayout(false);
@@ -404,7 +496,11 @@ namespace CreamInstaller.Forms
private CustomTreeView selectionTreeView;
private CheckBox blockedGamesCheckBox;
private Button blockProtectedHelpButton;
private CheckBox useSmokeAPICheckBox;
private Button useSmokeAPIHelpButton;
private FlowLayoutPanel blockedGamesFlowPanel;
private FlowLayoutPanel useSmokeAPILayoutPanel;
private FlowLayoutPanel darkModeFlowPanel;
private FlowLayoutPanel allCheckBoxLayoutPanel;
private Button uninstallButton;
private Label progressLabelGames;
@@ -416,6 +512,8 @@ namespace CreamInstaller.Forms
private Button loadButton;
private Button resetButton;
private FlowLayoutPanel saveFlowPanel;
private TableLayoutPanel topOptionsTable;
private CheckBox darkModeCheckBox;
}
}
+59 -10
View File
@@ -35,7 +35,7 @@ internal sealed partial class SelectForm : CustomForm
private SelectForm()
{
InitializeComponent();
selectionTreeView.TreeViewNodeSorter = PlatformIdComparer.NodeName;
selectionTreeView.TreeViewNodeSorter = sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
Text = Program.ApplicationName;
}
@@ -109,7 +109,12 @@ internal sealed partial class SelectForm : CustomForm
UpdateRemainingDLCs();
});
}
private static async Task<T> WithTimeout<T>(Task<T> task, int millisecondsTimeout)
{
if (await Task.WhenAny(task, Task.Delay(millisecondsTimeout)) == task)
return await task;
return default;
}
private async Task GetApplicablePrograms(IProgress<int> progress, bool uninstallAll = false)
{
if (!uninstallAll && (programsToScan is null || programsToScan.Count < 1))
@@ -199,7 +204,7 @@ internal sealed partial class SelectForm : CustomForm
return;
StoreAppData storeAppData = await SteamStore.QueryStoreAPI(appId);
_ = Interlocked.Decrement(ref steamGamesToCheck);
CmdAppData cmdAppData = await SteamCMD.GetAppInfo(appId, branch, buildId);
CmdAppData cmdAppData = await WithTimeout(SteamCMD.GetAppInfo(appId, branch, buildId), 16000);
if (storeAppData is null && cmdAppData is null)
{
RemoveFromRemainingGames(name);
@@ -246,7 +251,7 @@ internal sealed partial class SelectForm : CustomForm
}
else
{
CmdAppData dlcCmdAppData = await SteamCMD.GetAppInfo(dlcAppId);
CmdAppData dlcCmdAppData = await WithTimeout(SteamCMD.GetAppInfo(dlcAppId), 16000);
if (dlcCmdAppData is not null)
{
dlcName = dlcCmdAppData.Common?.Name;
@@ -341,7 +346,7 @@ internal sealed partial class SelectForm : CustomForm
selection.Icon = IconGrabber.SteamAppImagesPath + @$"\{appId}\{cmdAppData?.Common?.Icon}.jpg";
selection.SubIcon = storeAppData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
+ @$"\{appId}\{cmdAppData?.Common?.ClientIcon}.ico";
selection.Publisher = storeAppData?.Publishers[0] ?? cmdAppData?.Extended?.Publisher;
selection.Publisher = storeAppData?.Publishers?.FirstOrDefault() ?? cmdAppData?.Extended?.Publisher;
selection.Website = storeAppData?.Website;
if (Program.Canceled)
return;
@@ -548,6 +553,8 @@ internal sealed partial class SelectForm : CustomForm
Program.Canceled = false;
blockedGamesCheckBox.Enabled = false;
blockProtectedHelpButton.Enabled = false;
useSmokeAPICheckBox.Enabled = false;
useSmokeAPIHelpButton.Enabled = false;
cancelButton.Enabled = true;
scanButton.Enabled = false;
noneFoundLabel.Visible = false;
@@ -694,6 +701,8 @@ internal sealed partial class SelectForm : CustomForm
scanButton.Enabled = true;
blockedGamesCheckBox.Enabled = true;
blockProtectedHelpButton.Enabled = true;
useSmokeAPICheckBox.Enabled = true;
useSmokeAPIHelpButton.Enabled = true;
}
private void OnTreeViewNodeCheckedChanged(object sender, TreeViewEventArgs e)
@@ -887,8 +896,8 @@ internal sealed partial class SelectForm : CustomForm
foreach (string directory in directories)
{
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string config,
out string log);
out string api64_o, out string old_config, out string config,
out string old_log, out string log);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists() ||
config.FileExists() || log.FileExists())
_ = items.Add(new ContextMenuItem($"Open EOS Directory #{++epic}", "File Explorer",
@@ -964,7 +973,7 @@ internal sealed partial class SelectForm : CustomForm
private void OnLoad(object sender, EventArgs _)
{
retry:
retry:
try
{
HideProgressBar();
@@ -1095,7 +1104,7 @@ internal sealed partial class SelectForm : CustomForm
private static bool CanLoadProxy() => ProgramData.ReadProxyChoices().Any();
private bool CanLoadSelections() => CanLoadDlc() || CanLoadProxy();
private static bool CanLoadSelections() => CanLoadDlc() || CanLoadProxy();
private void OnLoadSelections(object sender, EventArgs e)
{
@@ -1171,7 +1180,7 @@ internal sealed partial class SelectForm : CustomForm
saveButton.Enabled = CanSaveSelections();
resetButton.Enabled = CanResetSelections();
proxyAllCheckBox.CheckedChanged -= OnProxyAllCheckBoxChanged;
proxyAllCheckBox.Checked = Selection.All.Keys.All(selection => selection.UseProxy);
proxyAllCheckBox.Checked = Selection.All.Keys.Count != 0 && Selection.All.Keys.All(selection => selection.UseProxy);
proxyAllCheckBox.CheckedChanged += OnProxyAllCheckBoxChanged;
}
@@ -1206,8 +1215,48 @@ internal sealed partial class SelectForm : CustomForm
: blockedDirectoryExceptions),
customFormText: "Block Protected Games");
}
private void OnUseSmokeAPICheckBoxChanged(object sender, EventArgs e)
{
Program.UseSmokeAPI = useSmokeAPICheckBox.Checked;
OnLoad(forceProvideChoices: false);
}
private void OnUseSmokeAPIHelpButtonClicked(object sender, EventArgs e)
{
using DialogForm form = new(this);
_ = form.Show(SystemIcons.Information,
"[Experimental] WARNING: This may still be unstable.\n" +
"This setting restores the use of SmokeAPI.\n" +
"If some games don't launch with SmokeAPI enabled, try disabling this setting then Generate and Install again.",
customFormText: "Use SmokeAPI");
}
private void OnSortCheckBoxChanged(object sender, EventArgs e)
=> selectionTreeView.TreeViewNodeSorter =
sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
private void programsGroupBox_Enter(object sender, EventArgs e)
{
}
private void OnDarkModeCheckBoxChanged(object sender, EventArgs e)
{
bool requestedDark = darkModeCheckBox.Checked;
if (Program.DarkModeEnabled != requestedDark)
{
Program.DarkModeEnabled = requestedDark;
ThemeManager.Apply(this);
}
else
ThemeManager.Apply(this);
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
ThemeManager.Apply(this);
if (darkModeCheckBox is not null)
darkModeCheckBox.Checked = Program.DarkModeEnabled;
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Microsoft ResX Schema
Version 2.0
@@ -48,7 +48,7 @@
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+1
View File
@@ -40,6 +40,7 @@ internal sealed partial class UpdateForm : CustomForm
#if DEBUG
DebugForm.Current.Attach(form);
#endif
ThemeManager.Apply(form); // apply current theme when transitioning
}
private async void OnLoad()
+1 -1
View File
@@ -20,7 +20,7 @@ internal static class EpicLibrary
epicManifestsPath ??=
Registry.GetValue(@"HKEY_CURRENT_USER\Software\Epic Games\EOS", "ModSdkMetadataDir", null) as string;
epicManifestsPath ??=
Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Epic Games\EpicGamesLauncher", "AppDataPath",
Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Epic Games\EpicGamesLauncher", "AppDataPath",
null) as string;
if (epicManifestsPath is not null && epicManifestsPath.EndsWith(@"\Data", StringComparison.Ordinal))
epicManifestsPath += @"\Manifests";
+23 -1
View File
@@ -8,6 +8,10 @@ using CreamInstaller.Platforms.Epic.GraphQL;
using CreamInstaller.Utility;
using Newtonsoft.Json;
#if DEBUG
using CreamInstaller.Forms;
#endif
namespace CreamInstaller.Platforms.Epic;
internal static class EpicStore
@@ -19,11 +23,22 @@ internal static class EpicStore
{
List<(string id, string name, string product, string icon, string developer)> dlcIds = [];
string cacheFile = ProgramData.AppInfoPath + @$"\{categoryNamespace}.json";
string fileContent = cacheFile.ReadFile();
if (string.IsNullOrWhiteSpace(fileContent) || fileContent.Trim() == "null")
{
cacheFile.DeleteFile();
}
bool cachedExists = cacheFile.FileExists();
Response response = null;
if (!cachedExists || ProgramData.CheckCooldown(categoryNamespace, Cooldown))
{
response = await QueryGraphQL(categoryNamespace);
#if DEBUG
if (response is null)
{
DebugForm.Current.Log("ES: QueryGraphQL returned null");
}
#endif
try
{
cacheFile.WriteFile(JsonConvert.SerializeObject(response, Formatting.Indented));
@@ -114,6 +129,8 @@ internal static class EpicStore
dlcIds.Add((id, title, product, icon, developer));
}
public static bool EpicBool = true;
private static async Task<Response> QueryGraphQL(string categoryNamespace)
{
try
@@ -125,9 +142,14 @@ internal static class EpicStore
content.Headers.ContentType = new("application/json");
HttpClient client = HttpClientManager.HttpClient;
if (client is null)
{
#if DEBUG
DebugForm.Current.Log("ES: Client returned null");
#endif
return null;
}
HttpResponseMessage httpResponse =
await client.PostAsync(new Uri("https://graphql.epicgames.com/graphql"), content);
await client.PostAsync(new Uri("https://launcher.store.epicgames.com/graphql"), content);
_ = httpResponse.EnsureSuccessStatusCode();
string response = await httpResponse.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Response>(response);
@@ -111,7 +111,7 @@ internal static class ParadoxLauncher
if (steamOriginalSdk64 is null && api64.FileExists() &&
!api64.IsResourceFile(ResourceIdentifier.Steamworks64))
steamOriginalSdk64 = api64.ReadFileBytes(true);
directory.GetScreamApiComponents(out api32, out api32_o, out api64, out api64_o, out _, out _);
directory.GetScreamApiComponents(out api32, out api32_o, out api64, out api64_o, out _, out _, out _, out _);
screamInstalled = screamInstalled || api32_o.FileExists() || api64_o.FileExists()
|| api32.FileExists() && api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32)
|| api64.FileExists() && api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64);
@@ -165,7 +165,7 @@ internal static class ParadoxLauncher
else
await CreamAPI.Install(directory, selection, generateConfig: false);
directory.GetScreamApiComponents(out api32, out _, out api64, out _, out _, out _);
directory.GetScreamApiComponents(out api32, out _, out api64, out _, out _, out _, out _, out _);
if (epicOriginalSdk32 is not null && api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
{
epicOriginalSdk32.WriteResource(api32);
+9 -4
View File
@@ -19,7 +19,7 @@ internal static class Program
? index
: Application.ProductVersion.Length)];
internal const string RepositoryOwner = "pointfeev";
internal const string RepositoryOwner = "FroggMaster";
internal static readonly string RepositoryName = Name;
internal static readonly string RepositoryPackage = Name + ".zip";
internal static readonly string RepositoryExecutable = Name + ".exe";
@@ -35,14 +35,17 @@ internal static class Program
internal static readonly string CurrentProcessFilePath = CurrentProcess.MainModule?.FileName;
internal static readonly int CurrentProcessId = CurrentProcess.Id;
// this may forever be false, but who knows, maybe acidicoala makes it once again better than CreamAPI some day
internal const bool UseSmokeAPI = false;
// Setting is now toggleable. Huzzah!
internal static bool UseSmokeAPI = true;
internal static bool BlockProtectedGames = true;
internal static readonly string[] ProtectedGames = ["PAYDAY 2"];
internal static readonly string[] ProtectedGameDirectories = [@"\EasyAntiCheat", @"\BattlEye"];
internal static readonly string[] ProtectedGameDirectoryExceptions = [];
// Dark mode enabled by default
internal static bool DarkModeEnabled = true;
internal static bool IsGameBlocked(string name, string directory = null)
=> BlockProtectedGames && (ProtectedGames.Contains(name) || directory is not null &&
!ProtectedGameDirectoryExceptions.Contains(name)
@@ -70,6 +73,8 @@ internal static class Program
#if DEBUG
DebugForm.Current.Attach(form);
#endif
// Apply initial theme (dark by default)
Utility.ThemeManager.Apply(form);
Application.Run(form);
}
catch (Exception e)
@@ -97,4 +102,4 @@ internal static class Program
Cleanup();
HttpClientManager.Dispose();
}
}
}
+8 -13
View File
@@ -37,19 +37,14 @@ internal static class CreamAPI
_ = dlc.Add(extraDlc);
config.DeleteFile();
if (dlc.Count > 0)
{
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.Default);
WriteConfig(writer, selection.Name, !int.TryParse(selection.Id, out _) ? "0" : selection.Id,
new(dlc.ToDictionary(_dlc => _dlc.Id, _dlc => _dlc.Name), PlatformIdComparer.String), installForm);
writer.Flush();
writer.Close();
return;
}
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.Default);
WriteConfig(writer, selection.Name, !int.TryParse(selection.Id, out _) ? "0" : selection.Id,
new(dlc.ToDictionary(_dlc => _dlc.Id, _dlc => _dlc.Name), PlatformIdComparer.String), installForm);
writer.Flush();
writer.Close();
return;
}
private static void WriteConfig(StreamWriter writer, string name, string appId,
+60 -17
View File
@@ -35,10 +35,11 @@ internal static class Koaloader
into resource
select directory + @"\" + resource;
internal static void GetKoaloaderComponents(this string directory, out string old_config, out string config)
internal static void GetKoaloaderComponents(this string directory, out string old_config, out string config, out string log)
{
old_config = directory + @"\Koaloader.json";
config = directory + @"\Koaloader.config.json";
log = directory + @"\Koaloader.log";
}
private static void WriteProxy(this string path, string proxyName, BinaryType binaryType)
@@ -66,7 +67,7 @@ internal static class Koaloader
private static void CheckConfig(string directory, InstallForm installForm = null)
{
directory.GetKoaloaderComponents(out string old_config, out string config);
directory.GetKoaloaderComponents(out string old_config, out string config, out _);
if (old_config.FileExists())
{
if (!config.FileExists())
@@ -86,28 +87,26 @@ internal static class Koaloader
SortedList<string, string> targets = new(PlatformIdComparer.String);
SortedList<string, string> modules = new(PlatformIdComparer.String);
if (targets.Count > 0 || modules.Count > 0)
{
/*if (installForm is not null)
installForm.UpdateUser("Generating Koaloader configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, targets, modules, installForm);
writer.Flush();
writer.Close();
}
else if (config.FileExists())
if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
/*if (installForm is not null)
installForm.UpdateUser("Generating Koaloader configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, targets, modules, installForm);
writer.Flush();
writer.Close();
}
private static void WriteConfig(StreamWriter writer, SortedList<string, string> targets,
SortedList<string, string> modules, InstallForm installForm = null)
{
writer.WriteLine("{");
/*writer.WriteLine(" \"$schema\": \"https://raw.githubusercontent.com/acidicoala/Koaloader/refs/tags/v3.0.4/res/Koaloader.schema.json\",");*/
writer.WriteLine(" \"logging\": false,");
writer.WriteLine(" \"enabled\": true,");
writer.WriteLine(" \"auto_load\": " + (modules.Count > 0 ? "false" : "true") + ",");
@@ -122,10 +121,10 @@ internal static class Koaloader
installForm?.UpdateUser($"Added target to Koaloader.json with path {path}", LogTextBox.Action, false);
}
writer.WriteLine(" ]");
writer.WriteLine(" ],");
}
else
writer.WriteLine(" \"targets\": []");
writer.WriteLine(" \"targets\": [],");
if (modules.Count > 0)
{
@@ -153,7 +152,7 @@ internal static class Koaloader
bool deleteConfig = true)
=> await Task.Run(async () =>
{
directory.GetKoaloaderComponents(out string old_config, out string config);
directory.GetKoaloaderComponents(out string old_config, out string config, out string log);
foreach (string proxyPath in directory.GetKoaloaderProxies().Where(proxyPath
=> proxyPath.FileExists() && proxyPath.IsResourceFile(ResourceIdentifier.Koaloader)))
{
@@ -771,7 +770,51 @@ internal static class Koaloader
"85AD3B263735871F4606EF4AB98B9BBC", // Koaloader v3.0.2
"4207947D0452C1E33428ED098DC23D26", // Koaloader v3.0.2
"BDD0DCAE7A5FBBBA0D8B857AC34BD43C", // Koaloader v3.0.2
"A0933D21552CC5C835416DFD7604548D" // Koaloader v3.0.2
"A0933D21552CC5C835416DFD7604548D", // Koaloader v3.0.2
"51C6BF6DA8C9B2E80249A3F74F5F2836", // Koaloader v3.0.4
"9DCB246925667F0C34B306D356AEE8DA", // Koaloader v3.0.4
"1BC45223E417D4AE2A95F46DB71DDD8B", // Koaloader v3.0.4
"0286878E70A95C6AB93F8E2A944501CD", // Koaloader v3.0.4
"FAC5739AF157D3245DEF458D6304D902", // Koaloader v3.0.4
"2EAA174056BFA68AA22C43CBE6388329", // Koaloader v3.0.4
"FA736AC428269ADE76F8795F8104FA39", // Koaloader v3.0.4
"69A71B497A01147744CD204810ABBAD2", // Koaloader v3.0.4
"ABDD0483D79276362A66E48869CFCF6B", // Koaloader v3.0.4
"B544F93FFC46AFD8E5AC3FBA7930DB58", // Koaloader v3.0.4
"6A11F1E24CBD0518EDDEB28A7237CE87", // Koaloader v3.0.4
"7344E1F82B8E8AC08CC135F3858A1C59", // Koaloader v3.0.4
"126DE0C021297F826F91176962B2EDF5", // Koaloader v3.0.4
"2AC92E07DD269C5027A13E3F80C4A89A", // Koaloader v3.0.4
"7EB835E0B131D9A4F3283D15290A16CF", // Koaloader v3.0.4
"0E478B8AACDB2A8ED6038707CFBFC8E4", // Koaloader v3.0.4
"88A12C9B394C5EC2A72BDAE57F10A814", // Koaloader v3.0.4
"F4440A71D0F5D49C1ECC860DE9E3EEE6", // Koaloader v3.0.4
"C74AD1D21DFD141A91B9699DB298FFB3", // Koaloader v3.0.4
"3D7AFD5BAED9BB023A8BAB8715857C45", // Koaloader v3.0.4
"D982F9E2066877C26193109BD0C90815", // Koaloader v3.0.4
"708A3AA98C53CC1E23104544F54C6C22", // Koaloader v3.0.4
"614119A6452F1EC5B855BBBF3D66D6DE", // Koaloader v3.0.4
"D9971AE010AA8262AED30A4376CF32B2", // Koaloader v3.0.4
"045F9154B561705A88DB2F1C6E44D412", // Koaloader v3.0.4
"46629A0974EFFF141C7295B4204F5B60", // Koaloader v3.0.4
"A8AABF2BC2711BA73F9BAFEC9C9D848D", // Koaloader v3.0.4
"FF540D977C0DD9E32D9D452824ECDB96", // Koaloader v3.0.4
"E3F2E6E347BA407D189C8E3DAC58178C", // Koaloader v3.0.4
"383025E324DA842C9F6499E39B1AAB5B", // Koaloader v3.0.4
"20143E97CA1B2B9F729F84FDEE1C0CE4", // Koaloader v3.0.4
"9E6F063F0966C6848E7C15214ACD8774", // Koaloader v3.0.4
"A5EAC4FD9D174EDB8C8570A6FC018254", // Koaloader v3.0.4
"C73B276EBA0B3EBB4ECF0D4BED5E18E6", // Koaloader v3.0.4
"6A6E803C1C8CC93902166BA949FBFF5A", // Koaloader v3.0.4
"6DD915CF4FE47037F9BCBACE2CD36115", // Koaloader v3.0.4
"458AC3E7DD29824A418D23A2B09CC23A", // Koaloader v3.0.4
"F90EB4C46FB1B7ECA985C1CA245F9CBA", // Koaloader v3.0.4
"73F4D0F5C8B3033A04660CD2B27646FC", // Koaloader v3.0.4
"894F5D28EEA75A1F0B8172D0B06FA40E", // Koaloader v3.0.4
"4ECE60B4EAC0461BF33AF0A6359D3679", // Koaloader v3.0.4
"615A6A863A2F8876A1B55B09F5363A03", // Koaloader v3.0.4
"C5BD334FA0DDDD7E5A6FBDBF836C2FE5", // Koaloader v3.0.4
"77E8E2F05AA94D5AB03F5DE506D6B639" // Koaloader v3.0.4
]
};
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -174,8 +174,8 @@ internal static class Resources
if (platform is Platform.Epic or Platform.Paradox)
{
subDirectory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string config,
out string log);
out string api64_o, out string old_config, out string config,
out string old_log, out string log);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists()
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
_ = dllDirectories.Add(subDirectory);
+38 -36
View File
@@ -14,19 +14,21 @@ internal static class ScreamAPI
{
internal static void GetScreamApiComponents(this string directory, out string api32, out string api32_o,
out string api64, out string api64_o,
out string config, out string log)
out string old_config, out string config, out string old_log, out string log)
{
api32 = directory + @"\EOSSDK-Win32-Shipping.dll";
api32_o = directory + @"\EOSSDK-Win32-Shipping_o.dll";
api64 = directory + @"\EOSSDK-Win64-Shipping.dll";
api64_o = directory + @"\EOSSDK-Win64-Shipping_o.dll";
config = directory + @"\ScreamAPI.json";
log = directory + @"\ScreamAPI.log";
old_config = directory + @"\ScreamAPI.json";
config = directory + @"\ScreamAPI.config.json";
old_log = directory + @"\ScreamAPI.log";
log = directory + @"\ScreamAPI.log.log";
}
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
{
directory.GetScreamApiComponents(out _, out _, out _, out _, out string config, out _);
directory.GetScreamApiComponents(out _, out _, out _, out _, out string old_config, out string config, out _, out _);
HashSet<SelectionDLC> overrideCatalogItems =
selection.DLC.Where(dlc => dlc.Type is DLCType.Epic && !dlc.Enabled).ToHashSet();
int entitlementCount = 0;
@@ -52,62 +54,60 @@ internal static class ScreamAPI
if (injectedEntitlements.Count == entitlementCount)
injectedEntitlements.Clear();
if (overrideCatalogItems.Count > 0 || injectedEntitlements.Count > 0)
{
/*if (installForm is not null)
installForm.UpdateUser("Generating ScreamAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer,
new(overrideCatalogItems.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
new(injectedEntitlements.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
else if (config.FileExists())
if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
/*if (installForm is not null)
installForm.UpdateUser("Generating ScreamAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer,
new(overrideCatalogItems.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
new(injectedEntitlements.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
private static void WriteConfig(StreamWriter writer, SortedList<string, SelectionDLC> overrideCatalogItems,
SortedList<string, SelectionDLC> injectedEntitlements, InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"version\": 2,");
/*writer.WriteLine(" \"$schema\": \"https://raw.githubusercontent.com/acidicoala/ScreamAPI/refs/tags/v4.0.0/res/ScreamAPI.schema.json\",");*/
writer.WriteLine(" \"$version\": 3,");
writer.WriteLine(" \"logging\": false,");
writer.WriteLine(" \"eos_logging\": false,");
writer.WriteLine(" \"log_eos\": false,");
writer.WriteLine(" \"block_metrics\": false,");
writer.WriteLine(" \"catalog_items\": {");
writer.WriteLine(" \"unlock_all\": true,");
writer.WriteLine(" \"namespace_id\": \"\",");
writer.WriteLine(" \"default_dlc_status\": \"unlocked\",");
if (overrideCatalogItems.Count > 0)
{
writer.WriteLine(" \"override\": [");
writer.WriteLine(" \"override_dlc_status\": {");
KeyValuePair<string, SelectionDLC> lastOverrideCatalogItem = overrideCatalogItems.Last();
foreach (KeyValuePair<string, SelectionDLC> pair in overrideCatalogItems)
{
SelectionDLC selectionDlc = pair.Value;
writer.WriteLine($" \"{selectionDlc.Id}\"{(pair.Equals(lastOverrideCatalogItem) ? "" : ",")}");
writer.WriteLine($" \"{selectionDlc.Id}\": \"locked\"{(pair.Equals(lastOverrideCatalogItem) ? "" : ",")}");
installForm?.UpdateUser(
$"Added locked catalog item to ScreamAPI.json with id {selectionDlc.Id} ({selectionDlc.Name})",
LogTextBox.Action,
false);
}
writer.WriteLine(" ]");
writer.WriteLine(" },");
}
else
writer.WriteLine(" \"override\": []");
writer.WriteLine(" \"override_dlc_status\": {},");
writer.WriteLine(" },");
writer.WriteLine(" \"entitlements\": {");
if (injectedEntitlements.Count > 0)
writer.WriteLine(" \"extra_graphql_endpoints\": [],");
writer.WriteLine(" \"extra_entitlements\": {}");
/*if (injectedEntitlements.Count > 0)
{
writer.WriteLine(" \"unlock_all\": false,");
writer.WriteLine(" \"auto_inject\": false,");
writer.WriteLine(" \"default_dlc_status\": original,");
writer.WriteLine(" \"inject\": [");
KeyValuePair<string, SelectionDLC> lastEntitlement = injectedEntitlements.Last();
foreach (KeyValuePair<string, SelectionDLC> pair in injectedEntitlements)
@@ -129,7 +129,7 @@ internal static class ScreamAPI
writer.WriteLine(" \"inject\": []");
}
writer.WriteLine(" }");
writer.WriteLine(" }");*/
writer.WriteLine("}");
}
@@ -137,7 +137,7 @@ internal static class ScreamAPI
=> await Task.Run(() =>
{
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
out string config, out string log);
out string old_config, out string config, out string old_log, out string log);
if (api32_o.FileExists())
{
if (api32.FileExists())
@@ -184,7 +184,7 @@ internal static class ScreamAPI
=> await Task.Run(() =>
{
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
out _, out _);
out _, out _, out _, out _);
if (api32.FileExists() && !api32_o.FileExists())
{
api32.MoveFile(api32_o!, true);
@@ -221,13 +221,15 @@ internal static class ScreamAPI
[
"069A57B1834A960193D2AD6B96926D70", // ScreamAPI v3.0.0
"E2FB3A4A9583FDC215832E5F935E4440", // ScreamAPI v3.0.1
"8B4B30AFAE8D7B06413EE2F2266B20DB" // ScreamAPI v4.0.0-rc01
"8B4B30AFAE8D7B06413EE2F2266B20DB", // ScreamAPI v4.0.0-rc01
"F2C1A6B3EF73ED14E810851DBF418453" // ScreamAPI v4.0.0
],
[ResourceIdentifier.EpicOnlineServices64] =
[
"0D62E57139F1A64F807A9934946A9474", // ScreamAPI v3.0.0
"3875C7B735EE80C23239CC4749FDCBE6", // ScreamAPI v3.0.1
"CBC89E2221713B0D4482F91282030A88" // ScreamAPI v4.0.0-rc01
"CBC89E2221713B0D4482F91282030A88", // ScreamAPI v4.0.0-rc01
"2F98D62283AA024CBD756921B9533489" // ScreamAPI v4.0.0
]
};
}
+89 -22
View File
@@ -12,6 +12,11 @@ namespace CreamInstaller.Resources;
internal static class SmokeAPI
{
internal static readonly List<string> ProxyDLLs = ["winmm", "winhttp", "version"];
internal static IEnumerable<string> GetSmokeApiProxies(this string directory)
=> from proxy in ProxyDLLs select directory + @"\" + proxy + ".dll";
internal static void GetSmokeApiComponents(this string directory, out string api32, out string api32_o,
out string api64, out string api64_o,
out string old_config, out string config, out string old_log, out string log, out string cache)
@@ -59,27 +64,23 @@ internal static class SmokeAPI
false);
}
if (selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any()) || overrideDlc.Count > 0 ||
injectDlc.Count > 0)
{
/*if (installForm is not null)
installForm.UpdateUser("Generating SmokeAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, selection.Id,
new(extraApps.ToDictionary(extraApp => extraApp.Key, extraApp => extraApp.Value),
PlatformIdComparer.String),
new(overrideDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
new(injectDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
writer.Flush();
writer.Close();
}
else if (config.FileExists())
if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
/*if (installForm is not null)
installForm.UpdateUser("Generating SmokeAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, selection.Id,
new(extraApps.ToDictionary(extraApp => extraApp.Key, extraApp => extraApp.Value),
PlatformIdComparer.String),
new(overrideDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
new(injectDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
writer.Flush();
writer.Close();
}
private static void WriteConfig(StreamWriter writer, string appId,
@@ -88,9 +89,10 @@ internal static class SmokeAPI
InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"$version\": 2,");
/*writer.WriteLine(" \"$schema\": \"https://raw.githubusercontent.com/acidicoala/SmokeAPI/refs/tags/v4.0.0/res/SmokeAPI.schema.json\",");*/
writer.WriteLine(" \"$version\": 4,");
writer.WriteLine(" \"logging\": false,");
writer.WriteLine(" \"unlock_family_sharing\": true,");
writer.WriteLine(" \"log_steam_http\": false,");
writer.WriteLine(" \"default_app_status\": \"unlocked\",");
writer.WriteLine(" \"override_app_status\": {},");
if (overrideDlc.Count > 0)
@@ -168,9 +170,8 @@ internal static class SmokeAPI
writer.WriteLine(" },");
}
else
writer.WriteLine(" \"extra_dlcs\": {},");
writer.WriteLine(" \"extra_dlcs\": {}");
writer.WriteLine(" \"store_config\": null");
writer.WriteLine("}");
}
@@ -295,6 +296,60 @@ internal static class SmokeAPI
CheckConfig(directory, selection, installForm);
});
internal static async Task ProxyUninstall(string directory, InstallForm installForm = null,
bool deleteOthers = true)
=> await Task.Run(() =>
{
foreach (string proxy in directory.GetSmokeApiProxies().Where(proxy =>
proxy.FileExists() && (proxy.IsResourceFile(ResourceIdentifier.Steamworks32) ||
proxy.IsResourceFile(ResourceIdentifier.Steamworks64))))
{
proxy.DeleteFile(true);
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(proxy)}", LogTextBox.Action, false);
}
if (!deleteOthers)
return;
directory.GetSmokeApiComponents(out _, out _, out _, out _, out string old_config, out string config, out _,
out _, out _);
if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
}
});
internal static async Task ProxyInstall(string directory, BinaryType binaryType, Selection selection,
InstallForm installForm = null, bool generateConfig = true)
=> await Task.Run(async () =>
{
await Koaloader.Uninstall(directory, selection.RootDirectory, installForm);
string proxy = selection.Proxy ?? Selection.DefaultProxy;
string path = directory + @"\" + proxy + ".dll";
foreach (string _path in directory.GetSmokeApiProxies().Where(p =>
p != path && p.FileExists() && (p.IsResourceFile(ResourceIdentifier.Steamworks32) ||
p.IsResourceFile(ResourceIdentifier.Steamworks64))))
{
_path.DeleteFile(true);
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(_path)}", LogTextBox.Action, false);
}
if (path.FileExists() && !path.IsResourceFile(ResourceIdentifier.Steamworks32) &&
!path.IsResourceFile(ResourceIdentifier.Steamworks64))
throw new CustomMessageException("A non-SmokeAPI DLL named " + proxy +
".dll already exists in this directory!");
(binaryType == BinaryType.BIT32 ? "SmokeAPI.steam_api.dll" : "SmokeAPI.steam_api64.dll")
.WriteManifestResource(path);
installForm?.UpdateUser(
$"Wrote {(binaryType == BinaryType.BIT32 ? "32-bit" : "64-bit")} SmokeAPI: {Path.GetFileName(path)}",
LogTextBox.Action,
false);
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
internal static readonly Dictionary<ResourceIdentifier, HashSet<string>> ResourceMD5s = new()
{
[ResourceIdentifier.Steamworks32] =
@@ -310,7 +365,13 @@ internal static class SmokeAPI
"C8E796DDD74F2C28996EE3F41938565C", // SmokeAPI v2.0.2
"8B075C6B272A172A014D5C9E60F13DF2", // SmokeAPI v2.0.3
"A3873569DECAD08962C46E88352E6DB1", // SmokeAPI v2.0.4
"4A1A823E5CF4FB861DD6BA94539D29C4" // SmokeAPI v2.0.5
"4A1A823E5CF4FB861DD6BA94539D29C4", // SmokeAPI v2.0.5
"EC153C0CCE476AFFB2458575930F11E6", // SmokeAPI v3.1.5
"E833ACE855245D5939EE36FF25D8B4A4", // SmokeAPI v4.0.0
"A2728FC65BFF3305F43F87CB6E3AE448", // SmokeAPI v4.1.0
"CA6B8DE96022A70C45E11FF6D0B55857", // SmokeAPI v4.1.1
"0438477117293DF1EAE1B4D87E8CE084", // SmokeAPI v4.1.2
"2B2413E3CCDA93C3821711D089129D34" // SmokeAPI v4.1.3
],
[ResourceIdentifier.Steamworks64] =
[
@@ -325,7 +386,13 @@ internal static class SmokeAPI
"CF9DF2E2EBA002DB98FE37FB1FB08FA8", // SmokeAPI v2.0.2
"E4DC2AF2B8B77A0C9BF9BFBBAEA11CF7", // SmokeAPI v2.0.3
"C0DDB49C9BFD3E05CBC1C61D117E93F9", // SmokeAPI v2.0.4
"F7C3064D5E3C892B168F504C21AC4923" // SmokeAPI v2.0.5
"F7C3064D5E3C892B168F504C21AC4923", // SmokeAPI v2.0.5
"5A6712770EC7CE589252706245E62C72", // SmokeAPI v3.1.5
"22DD39B16D3C10FDB044FDCB1BAE63B8", // SmokeAPI v4.0.0
"997656BEB55D1D87918D0BF96BD5312F", // SmokeAPI v4.1.0
"CD628177EC5D6303043E35DB6A83AB30", // SmokeAPI v4.1.1
"3AC05641AA561C11BE706782B5D3C49D", // SmokeAPI v4.1.2
"B87E96F9A52D98A957B252CDAB61CBE8" // SmokeAPI v4.1.3
]
};
}
Binary file not shown.
Binary file not shown.
+9 -12
View File
@@ -31,23 +31,20 @@ internal static class UplayR1
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection =>
extraSelection.DLC.Where(dlc => !dlc.Enabled)))
_ = blacklistDlc.Add(extraDlc);
if (blacklistDlc.Count > 0)
{
/*if (installForm is not null)
installForm.UpdateUser("Generating Uplay R1 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
else if (config.FileExists())
if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
/*if (installForm is not null)
installForm.UpdateUser("Generating Uplay R1 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
private static void WriteConfig(StreamWriter writer, SortedList<string, SelectionDLC> blacklistDlc,
+9 -12
View File
@@ -33,23 +33,20 @@ internal static class UplayR2
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection =>
extraSelection.DLC.Where(dlc => !dlc.Enabled)))
_ = blacklistDlc.Add(extraDlc);
if (blacklistDlc.Count > 0)
{
/*if (installForm is not null)
installForm.UpdateUser("Generating Uplay R2 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
else if (config.FileExists())
if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
/*if (installForm is not null)
installForm.UpdateUser("Generating Uplay R2 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
private static void WriteConfig(StreamWriter writer, SortedList<string, SelectionDLC> blacklistDlc,
+2
View File
@@ -45,6 +45,8 @@ internal sealed class Selection : IEquatable<Selection>
{
if (!Program.UseSmokeAPI && Platform is Platform.Steam or Platform.Paradox)
return CreamAPI.ProxyDLLs;
if (Program.UseSmokeAPI && Platform is Platform.Steam or Platform.Paradox)
return SmokeAPI.ProxyDLLs;
return EmbeddedResources.Where(r => r.StartsWith("Koaloader", StringComparison.Ordinal)).Select(p =>
{
p.GetProxyInfoFromIdentifier(out string proxyName, out _);
+9 -1
View File
@@ -20,7 +20,15 @@ internal static class HttpClientManager
internal static void Setup()
{
HttpClient = new();
HttpClient.DefaultRequestHeaders.UserAgent.Add(new(Program.Name, Program.Version));
if (CreamInstaller.Platforms.Epic.EpicStore.EpicBool)
{
HttpClient.DefaultRequestHeaders.UserAgent.Add(new("EpicGamesLauncher", "18.9.0-45233261+++Portal+Release-Live"));
CreamInstaller.Platforms.Epic.EpicStore.EpicBool = false;
}
else
{
HttpClient.DefaultRequestHeaders.UserAgent.Add(new(Program.Name, Program.Version));
}
HttpClient.DefaultRequestHeaders.AcceptLanguage.Add(new(CultureInfo.CurrentCulture.ToString()));
}
+5
View File
@@ -21,4 +21,9 @@ internal static partial class NativeImports
[LibraryImport("user32.dll", SetLastError = true), DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static partial void SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy,
uint uFlags);
// Windows theming (scrollbars / dark mode for some controls)
[LibraryImport("uxtheme.dll", SetLastError = true)]
internal static partial int SetWindowTheme(nint hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pszSubAppName,
[MarshalAs(UnmanagedType.LPWStr)] string pszSubIdList);
}
+206
View File
@@ -0,0 +1,206 @@
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace CreamInstaller.Utility;
internal static class ThemeManager
{
// VS-like dark colors
private static readonly Color DarkBack = ColorTranslator.FromHtml("#1E1E1E");
private static readonly Color DarkBackAlt = ColorTranslator.FromHtml("#252525");
private static readonly Color DarkBorder = ColorTranslator.FromHtml("#3F3F46");
private static readonly Color DarkFore = ColorTranslator.FromHtml("#D4D4D4");
private static readonly Color DarkForeDim = ColorTranslator.FromHtml("#9CA3AF");
private static readonly Color Accent = ColorTranslator.FromHtml("#0E639C");
private static readonly Color DarkLink = ColorTranslator.FromHtml("#64B5F6");
private static readonly Color LightBack = SystemColors.Control;
private static readonly Color LightBackAlt = SystemColors.ControlLightLight;
private static readonly Color LightFore = SystemColors.ControlText;
private static readonly Color LightBorder = SystemColors.ControlDark;
internal static void ToggleDarkMode(Form anyForm)
{
Program.DarkModeEnabled = !Program.DarkModeEnabled;
ApplyToAllOpenForms();
}
internal static void Apply(Form form)
{
if (form is null) return;
if (!Program.DarkModeEnabled)
{
Reset(form);
return;
}
form.SuspendLayout();
form.BackColor = DarkBack;
form.ForeColor = DarkFore;
ApplyTitleBar(form);
foreach (Control c in form.Controls)
ApplyControlTheme(c, true);
form.ResumeLayout(true);
}
private static void ApplyControlTheme(Control control, bool dark)
{
if (control is null) return;
foreach (Control child in control.Controls)
ApplyControlTheme(child, dark);
if (dark)
{
switch (control)
{
case GroupBox gb:
gb.ForeColor = DarkFore;
gb.BackColor = DarkBackAlt;
break;
case Button b:
b.FlatStyle = FlatStyle.Flat;
b.FlatAppearance.BorderColor = DarkBorder;
b.BackColor = DarkBackAlt;
b.ForeColor = DarkFore;
break;
case CheckBox cb:
cb.BackColor = DarkBack;
cb.ForeColor = DarkFore;
break;
case LinkLabel ll:
ll.BackColor = DarkBack;
ll.ForeColor = DarkFore; // normal text
ll.LinkColor = DarkLink;
ll.ActiveLinkColor = Color.White; // high contrast when pressed
ll.VisitedLinkColor = DarkLink; // keep consistent
break;
case Label lbl:
lbl.BackColor = DarkBack;
lbl.ForeColor = DarkFore;
break;
case ProgressBar pb:
pb.ForeColor = Accent;
pb.BackColor = DarkBackAlt;
break;
case TreeView tv:
tv.BackColor = DarkBackAlt;
tv.ForeColor = DarkFore;
tv.LineColor = DarkBorder;
break;
case RichTextBox rtb:
rtb.BackColor = DarkBackAlt;
rtb.ForeColor = DarkFore;
break;
case TableLayoutPanel tlp:
tlp.BackColor = DarkBack;
break;
case FlowLayoutPanel flp:
flp.BackColor = DarkBack;
break;
}
TryApplyScrollbarTheme(control, true);
}
else
{
// Light reset per control type
switch (control)
{
case GroupBox gb:
gb.BackColor = LightBack;
gb.ForeColor = LightFore;
break;
case Button b:
b.FlatStyle = FlatStyle.Standard;
b.BackColor = LightBack;
b.ForeColor = LightFore;
break;
case CheckBox cb:
cb.BackColor = LightBack;
cb.ForeColor = LightFore;
break;
case LinkLabel ll:
ll.BackColor = LightBack;
ll.ForeColor = LightFore;
// allow system defaults for link colors
ll.LinkColor = SystemColors.HotTrack;
ll.ActiveLinkColor = SystemColors.Highlight;
ll.VisitedLinkColor = SystemColors.HotTrack;
break;
case Label lbl:
lbl.BackColor = LightBack;
lbl.ForeColor = LightFore;
break;
case ProgressBar pb:
pb.BackColor = LightBack;
pb.ForeColor = LightFore;
break;
case TreeView tv:
tv.BackColor = LightBack;
tv.ForeColor = LightFore;
tv.LineColor = LightBorder;
break;
case RichTextBox rtb:
rtb.BackColor = LightBack;
rtb.ForeColor = LightFore;
break;
case TableLayoutPanel tlp:
tlp.BackColor = LightBack;
break;
case FlowLayoutPanel flp:
flp.BackColor = LightBack;
break;
}
TryApplyScrollbarTheme(control, false);
}
}
private static void Reset(Form form)
{
form.SuspendLayout();
form.BackColor = LightBack;
form.ForeColor = LightFore;
ApplyTitleBar(form);
foreach (Control c in form.Controls)
ApplyControlTheme(c, false);
form.ResumeLayout(true);
}
private static void ApplyToAllOpenForms()
{
foreach (Form openForm in Application.OpenForms.Cast<Form>())
Apply(openForm);
}
private static void ApplyTitleBar(Form form)
{
try
{
int useDark = Program.DarkModeEnabled ?1 :0;
NativeMethods.EnableDarkTitleBar(form.Handle, useDark);
}
catch { }
}
private static void TryApplyScrollbarTheme(Control control, bool dark)
{
// RichTextBox & TreeView host scrollbars internally; use window theme API
try
{
string theme = dark ? "DarkMode_Explorer" : null; // reset with null
NativeImports.SetWindowTheme(control.Handle, theme, null);
}
catch { }
}
}
internal static class NativeMethods
{
private const int DWMWA_USE_IMMERSIVE_DARK_MODE =20;
[System.Runtime.InteropServices.DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(System.IntPtr hwnd, int attr, ref int attrValue, int attrSize);
internal static void EnableDarkTitleBar(System.IntPtr handle, int useDark)
{
_ = DwmSetWindowAttribute(handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref useDark, sizeof(int));
}
}
+1
View File
@@ -3,6 +3,7 @@ $Array64 = [System.Text.StringBuilder]::new().AppendLine('[')
function Write-Hash([System.IO.FileInfo] $File, [string] $Version) {
$Hash = (Get-FileHash $File -Algorithm MD5).Hash
$Value = "`t`"$Hash`", // CreamAPI $Version"
$Value = "`t`"$Hash`", // SmokeAPI $Version"
if ($File.Name.Contains('64')) {
$Array64.AppendLine($Value) | Out-Null
} else {
+20 -12
View File
@@ -1,10 +1,11 @@
### CreamInstaller: Automatic DLC Unlocker Installer & Configuration Generator
### [Revived] CreamInstaller: Automatic DLC Unlocker Installer & Configuration Generator
[![Latest Release](https://img.shields.io/github/v/release/FroggMaster/CreamInstaller?label=latest%20release)](https://github.com/FroggMaster/CreamInstaller/releases/latest) [![CI Build](https://github.com/FroggMaster/CreamInstaller/actions/workflows/ci-builds.yml/badge.svg)](https://github.com/FroggMaster/CreamInstaller/actions/workflows/ci-builds.yml)
![Program Preview Image](https://raw.githubusercontent.com/pointfeev/CreamInstaller/main/preview.png)
![Program Preview Image](https://raw.githubusercontent.com/FroggMaster/CreamInstaller/main/preview.png)
###### **NOTE:** This is simply a preview image; this is not a list of supported games nor configurations!
##### The program utilizes the latest version of [CreamAPI](https://cs.rin.ru/forum/viewtopic.php?f=29&t=70576) by [deadmau5](https://cs.rin.ru/forum/viewtopic.php?f=29&t=70576). It also utilizes the latest versions of [Koaloader](https://github.com/acidicoala/Koaloader), ~~[SmokeAPI](https://github.com/acidicoala/SmokeAPI)~~, [ScreamAPI](https://github.com/acidicoala/ScreamAPI), [Uplay R1 Unlocker](https://github.com/acidicoala/UplayR1Unlocker) and [Uplay R2 Unlocker](https://github.com/acidicoala/UplayR2Unlocker), all by [acidicoala](https://github.com/acidicoala). All unlockers are downloaded and embedded into the program itself; no further downloads necessary on your part!
##### The program utilizes the latest version of [CreamAPI](https://cs.rin.ru/forum/viewtopic.php?f=29&t=70576) by [deadmau5](https://cs.rin.ru/forum/viewtopic.php?f=29&t=70576). It also utilizes the latest versions of [SmokeAPI](https://github.com/acidicoala/SmokeAPI), [Koaloader](https://github.com/acidicoala/Koaloader), [ScreamAPI](https://github.com/acidicoala/ScreamAPI), [Uplay R1 Unlocker](https://github.com/acidicoala/UplayR1Unlocker) and [Uplay R2 Unlocker](https://github.com/acidicoala/UplayR2Unlocker), all by [acidicoala](https://github.com/acidicoala). All unlockers are downloaded and embedded into the program itself; no further downloads necessary on your part!
---
#### Description:
Automatically finds all installed Steam, Epic and Ubisoft games with their respective DLC-related DLL locations on the user's computer,
@@ -26,11 +27,18 @@ games and DLCs the user selects; however, through the use of **right-click conte
* Automatic DLL installation and configuration generation for CreamAPI, Koaloader, ScreamAPI, Uplay R1 Unlocker and Uplay R2 Unlocker.
* Automatic uninstallation of DLLs and configurations for CreamAPI, Koaloader, SmokeAPI, ScreamAPI, Uplay R1 Unlocker and Uplay R2 Unlocker.
* Automatic reparation of the Paradox Launcher (and manually via the right-click context menu "Repair" option). *For when the launcher updates whilst you have CreamAPI, SmokeAPI or ScreamAPI installed to it.*
---
<details>
<summary><strong>Continuous Integration (CI) Builds</strong></summary>
- CreamInstaller is automatically built and tested using GitHub Actions on every push to the **main** branch. You can view all recent CI build runs by clicking the status badge at the top or here: [![CI Build](https://github.com/FroggMaster/CreamInstaller/actions/workflows/ci-builds.yml/badge.svg)](https://github.com/FroggMaster/CreamInstaller/actions/workflows/ci-builds.yml)
</details>
---
#### Installation:
1. Click [here](https://github.com/pointfeev/CreamInstaller/releases/latest/download/CreamInstaller.zip) to download the latest release from [GitHub](https://github.com/pointfeev/CreamInstaller).
2. Extract the executable from the ZIP file to anywhere on your computer you want. *It's completely self-contained.*
1. Click [here](https://github.com/FroggMaster/CreamInstaller/releases/latest/download/CreamInstaller.exe) to download the latest release from [GitHub](https://github.com/FroggMaster/CreamInstaller).
2. Move the executable to anywhere on your computer you want. *It's completely self-contained.*
If the program doesn't seem to launch, try downloading and installing [.NET Desktop Runtime 8.0.7](https://download.visualstudio.microsoft.com/download/pr/bb581716-4cca-466e-9857-512e2371734b/5fe261422a7305171866fd7812d0976f/windowsdesktop-runtime-8.0.7-win-x64.exe) and restarting your computer. Note that the program currently only supports Windows 10+ 64-bit machines as seen [here](https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md).
@@ -52,23 +60,23 @@ If the program doesn't seem to launch, try downloading and installing [.NET Desk
#### FAQ / Common Issues:
**Q:** The program is not launching.
**A:** First and foremost, note that the program currently only supports Windows 10+ 64-bit machines as seen [here](https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md). If that does not apply to you, then make sure you've extracted the executable from the ZIP file before you've launched it, resolved your anti-virus, and have tried downloading the .NET Desktop Runtime mentioned under [installation instructions](https://github.com/pointfeev/CreamInstaller#installation) above and restarting your computer. If none of the above work, then I simply cannot do anything about it, I do not control .NET. Either your system is not supported by the current version of .NET, or something is wrong/corrupted with your system.
**A:** First and foremost, note that the program currently only supports Windows 10+ 64-bit machines as seen [here](https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md). If that does not apply to you, then make sure you've extracted the executable from the ZIP file before you've launched it, resolved your anti-virus, and have tried downloading the .NET Desktop Runtime mentioned under [installation instructions](https://github.com/FroggMaster/CreamInstaller#installation) above and restarting your computer. If none of the above work, then I simply cannot do anything about it, I do not control .NET. Either your system is not supported by the current version of .NET, or something is wrong/corrupted with your system.
**Q:** The game I installed the unlocker(s) to is not working/the DLCs are not unlocked.
**A:** Make sure you've read the note under [Usage](https://github.com/pointfeev/CreamInstaller#usage) above! Assuming the program functioned as it was supposed to by properly installing DLC unlockers to your chosen games, this is not an issue I can do anything about and it's entirely up to you to seek the appropriate resources to fix it yourself (hint: https://cs.rin.ru/forum/viewforum.php?f=10).
**A:** Make sure you've read the note under [Usage](https://github.com/FroggMaster/CreamInstaller#usage) above! Assuming the program functioned as it was supposed to by properly installing DLC unlockers to your chosen games, this is not an issue I can do anything about and it's entirely up to you to seek the appropriate resources to fix it yourself (hint: https://cs.rin.ru/forum/viewforum.php?f=10).
**Q:** The program and/or files installed by the program are detected as a virus/trojan/malware.
**A:** The "issue" of the program's outputted Koaloader DLLs being detected as false positives such as Mamson.A!ac, Phonzy.A!ml, Wacatac.H!ml, Malgent!MSR, Tiggre!rfn, and many many others, has already been posted and explained dozens of times now in many different manners... please do not post it again, you will just be ignored; instead, refer to the explanations within issue #40 and its linked issues: https://github.com/pointfeev/CreamInstaller/issues/40.
**A:** The "issue" of the program's outputted Koaloader DLLs being detected as false positives such as Mamson.A!ac, Phonzy.A!ml, Wacatac.H!ml, Malgent!MSR, Tiggre!rfn, and many many others, has already been posted and explained dozens of times now in many different manners... please do not post it again, you will just be ignored; instead, refer to the explanations within issue #40 and its linked issues: [WebArchived Link: https://github.com/pointfeev/CreamInstaller/issues/40](https://web.archive.org/web/20240604162435/https://github.com/pointfeev/CreamInstaller/issues/40).
---
##### Bugs/Crashes/Issues:
For reliable and quick assistance, all bugs, crashes and other issues should be referred to the [GitHub Issues](https://github.com/pointfeev/CreamInstaller/issues) page!
For reliable and quick assistance, all bugs, crashes and other issues should be referred to the [GitHub Issues](https://github.com/FroggMaster/CreamInstaller/issues) page!
##### **HOWEVER**: Please read the [FAQ entry](https://github.com/pointfeev/CreamInstaller#faq--common-issues) above and/or [template issue](https://github.com/pointfeev/CreamInstaller/issues/new/choose) corresponding to your problem should one exist! Also, note that the [GitHub Issues](https://github.com/pointfeev/CreamInstaller/issues) page is not your personal assistance hotline, rather it is for genuine bugs/crashes/issues with the program itself. If you post an issue which is off-topic or has already been explained within the FAQ, template issues, and/or within this text in general, I will just close it and you will be ignored.
##### **HOWEVER**: Please read the [FAQ entry](https://github.com/FroggMaster/CreamInstaller#faq--common-issues) above and/or [template issue](https://github.com/FroggMaster/CreamInstaller/issues/new/choose) corresponding to your problem should one exist! Also, note that the [GitHub Issues](https://github.com/FroggMaster/CreamInstaller/issues) page is not your personal assistance hotline, rather it is for genuine bugs/crashes/issues with the program itself. If you post an issue which is off-topic or has already been explained within the FAQ, template issues, and/or within this text in general, I will just close it and you will be ignored.
---
##### More Information:
* SteamCMD installation and appinfo cache can be found at **C:\ProgramData\CreamInstaller**.
* The program automatically and very quickly updates from [GitHub](https://github.com/pointfeev/CreamInstaller) by choice of the user through a dialog on startup.
* The program source and other information can be found on [GitHub](https://github.com/pointfeev/CreamInstaller).
* The program automatically and very quickly updates from [GitHub](https://github.com/FroggMaster/CreamInstaller) by choice of the user through a dialog on startup.
* The program source and other information can be found on [GitHub](https://github.com/FroggMaster/CreamInstaller).
* Credit to [Mattahan](https://www.mattahan.com) for the program icon.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 36 KiB