From 6bb75a4049c6b11fd4a1843d78b01049a2e9661e Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Fri, 9 Oct 2026 17:22:05 +0300 Subject: [PATCH] [SharpEmu] Add bundled demo game --- .gitignore | 1 + src/SharpEmu.CLI/SharpEmu.CLI.csproj | 67 ++++++++++++++++++++++++++++ src/SharpEmu.GUI/BundledDemo.cs | 34 ++++++++++++++ src/SharpEmu.GUI/MainWindow.axaml.cs | 48 +++++++++++++------- 4 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 src/SharpEmu.GUI/BundledDemo.cs diff --git a/.gitignore b/.gitignore index 4403e8b..3aaef39 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ [Aa]rtifacts/ logs/ .tmp/ +src/SharpEmu.Demo/ x86/ x64/ diff --git a/src/SharpEmu.CLI/SharpEmu.CLI.csproj b/src/SharpEmu.CLI/SharpEmu.CLI.csproj index 7cc497b..dfe7ddc 100644 --- a/src/SharpEmu.CLI/SharpEmu.CLI.csproj +++ b/src/SharpEmu.CLI/SharpEmu.CLI.csproj @@ -180,4 +180,71 @@ SPDX-License-Identifier: GPL-2.0-or-later SkipUnchangedFiles="true" /> + + e3a6dd3 + demo + $(BaseIntermediateOutputPath)sharpemu-demo/$(SharpEmuDemoTag) + $(SharpEmuDemoCacheDir)/sharpemu-demo.zip + $([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '..', 'SharpEmu.Demo')) + $(SharpEmuDemoDir).tag + + + + + + + + <_SharpEmuDemoCurrent Condition="'$(SharpEmuDemoTag)' != '' And '$(_SharpEmuDemoExtractedTag)' == '$(SharpEmuDemoTag)'">true + + + + + + true + + + + + + + + + <_SharpEmuDemoFiles Include="$(SharpEmuDemoDir)**/*" Exclude="$(SharpEmuDemoStamp)" Condition="'$(SharpEmuDemoComplete)' == 'true'" /> + + + + + + + + <_SharpEmuDemoFiles Include="$(SharpEmuDemoDir)**/*" Exclude="$(SharpEmuDemoStamp)" Condition="'$(SharpEmuDemoComplete)' == 'true'" /> + + + + + diff --git a/src/SharpEmu.GUI/BundledDemo.cs b/src/SharpEmu.GUI/BundledDemo.cs new file mode 100644 index 0000000..31a8c5c --- /dev/null +++ b/src/SharpEmu.GUI/BundledDemo.cs @@ -0,0 +1,34 @@ +// Copyright (C) 2026 SharpEmu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +using System.IO; + +namespace SharpEmu.GUI; + +internal static class BundledDemo +{ + internal const string FolderName = "demo"; + + private static readonly string[] RequiredFiles = + [ + "eboot.bin", + Path.Combine("sce_sys", "param.json"), + Path.Combine("sce_sys", "icon0.png"), + Path.Combine("sce_sys", "pic0.png"), + Path.Combine("sce_sys", "snd0.at9"), + ]; + + internal static string? FindEboot(string baseDirectory) + { + var root = Path.Combine(baseDirectory, FolderName); + foreach (var file in RequiredFiles) + { + if (!File.Exists(Path.Combine(root, file))) + { + return null; + } + } + + return Path.GetFullPath(Path.Combine(root, "eboot.bin")); + } +} diff --git a/src/SharpEmu.GUI/MainWindow.axaml.cs b/src/SharpEmu.GUI/MainWindow.axaml.cs index ffb0962..567c893 100644 --- a/src/SharpEmu.GUI/MainWindow.axaml.cs +++ b/src/SharpEmu.GUI/MainWindow.axaml.cs @@ -2008,21 +2008,7 @@ public partial class MainWindow : Window continue; } - long size = 0; - try - { - size = new FileInfo(fullPath).Length; - } - catch (IOException exception) - { - Console.Error.WriteLine( - $"[GUI][WARN] Could not inspect executable '{fullPath}': {exception.Message}"); - } - - var (title, titleId, version) = TryReadParamJson(fullPath); - games.Add(new GameEntry( - title ?? GameNameFor(fullPath), titleId, version, fullPath, size, - FindCoverFor(fullPath), FindBackgroundFor(fullPath))); + games.Add(CreateGameEntry(fullPath)); } } catch (Exception exception) @@ -2033,9 +2019,41 @@ public partial class MainWindow : Window } games.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)); + AddBundledDemo(games, excludedPaths); return games; } + private static void AddBundledDemo(List games, IReadOnlySet excludedPaths) + { + var demo = BundledDemo.FindEboot(AppContext.BaseDirectory); + if (demo is null || excludedPaths.Contains(demo)) + { + return; + } + + games.RemoveAll(game => string.Equals(game.Path, demo, GameLibraryPath.Comparison)); + games.Insert(0, CreateGameEntry(demo)); + } + + private static GameEntry CreateGameEntry(string fullPath) + { + long size = 0; + try + { + size = new FileInfo(fullPath).Length; + } + catch (IOException exception) + { + Console.Error.WriteLine( + $"[GUI][WARN] Could not inspect executable '{fullPath}': {exception.Message}"); + } + + var (title, titleId, version) = TryReadParamJson(fullPath); + return new GameEntry( + title ?? GameNameFor(fullPath), titleId, version, fullPath, size, + FindCoverFor(fullPath), FindBackgroundFor(fullPath)); + } + /// /// Reads the game title, title id and content version from /// sce_sys/param.json next to the executable, when present.