[SharpEmu] Add bundled demo game

This commit is contained in:
ParantezTech 2026-10-09 17:22:05 +03:00
parent 0af8dce081
commit 6bb75a4049
4 changed files with 135 additions and 15 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@
[Aa]rtifacts/
logs/
.tmp/
src/SharpEmu.Demo/
x86/
x64/

View File

@ -180,4 +180,71 @@ SPDX-License-Identifier: GPL-2.0-or-later
SkipUnchangedFiles="true" />
</Target>
<PropertyGroup>
<SharpEmuDemoTag>e3a6dd3</SharpEmuDemoTag>
<SharpEmuDemoFolderName>demo</SharpEmuDemoFolderName>
<SharpEmuDemoCacheDir>$(BaseIntermediateOutputPath)sharpemu-demo/$(SharpEmuDemoTag)</SharpEmuDemoCacheDir>
<SharpEmuDemoArchive>$(SharpEmuDemoCacheDir)/sharpemu-demo.zip</SharpEmuDemoArchive>
<SharpEmuDemoDir>$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '..', 'SharpEmu.Demo'))</SharpEmuDemoDir>
<SharpEmuDemoStamp>$(SharpEmuDemoDir).tag</SharpEmuDemoStamp>
</PropertyGroup>
<Target Name="FetchSharpEmuDemo" BeforeTargets="Publish;Build">
<ReadLinesFromFile File="$(SharpEmuDemoStamp)" Condition="Exists('$(SharpEmuDemoStamp)')">
<Output TaskParameter="Lines" PropertyName="_SharpEmuDemoExtractedTag" />
</ReadLinesFromFile>
<PropertyGroup>
<_SharpEmuDemoCurrent Condition="'$(SharpEmuDemoTag)' != '' And '$(_SharpEmuDemoExtractedTag)' == '$(SharpEmuDemoTag)'">true</_SharpEmuDemoCurrent>
</PropertyGroup>
<DownloadFile
SourceUrl="https://github.com/sharpemu/sharpemu-demo/releases/download/$(SharpEmuDemoTag)/sharpemu-demo.zip"
DestinationFolder="$(SharpEmuDemoCacheDir)"
Condition="'$(SharpEmuDemoTag)' != '' And '$(_SharpEmuDemoCurrent)' != 'true' And !Exists('$(SharpEmuDemoArchive)')"
ContinueOnError="WarnAndContinue" />
<RemoveDir Directories="$(SharpEmuDemoDir)" Condition="'$(_SharpEmuDemoCurrent)' != 'true'" />
<Unzip
SourceFiles="$(SharpEmuDemoArchive)"
DestinationFolder="$(SharpEmuDemoDir)"
Condition="'$(SharpEmuDemoTag)' != '' And '$(_SharpEmuDemoCurrent)' != 'true' And Exists('$(SharpEmuDemoArchive)')"
ContinueOnError="WarnAndContinue" />
<PropertyGroup>
<SharpEmuDemoComplete Condition="Exists('$(SharpEmuDemoDir)eboot.bin') And Exists('$(SharpEmuDemoDir)sce_sys/param.json') And Exists('$(SharpEmuDemoDir)sce_sys/icon0.png') And Exists('$(SharpEmuDemoDir)sce_sys/pic0.png')">true</SharpEmuDemoComplete>
</PropertyGroup>
<WriteLinesToFile
File="$(SharpEmuDemoStamp)"
Lines="$(SharpEmuDemoTag)"
Overwrite="true"
Condition="'$(SharpEmuDemoComplete)' == 'true' And '$(_SharpEmuDemoCurrent)' != 'true'" />
<RemoveDir Directories="$(SharpEmuDemoDir)" Condition="'$(SharpEmuDemoComplete)' != 'true'" />
<Delete Files="$(SharpEmuDemoArchive)" Condition="'$(SharpEmuDemoComplete)' != 'true' And Exists('$(SharpEmuDemoArchive)')" />
</Target>
<Target Name="BuildSharpEmuDemo" AfterTargets="Build" DependsOnTargets="FetchSharpEmuDemo">
<ItemGroup>
<_SharpEmuDemoFiles Include="$(SharpEmuDemoDir)**/*" Exclude="$(SharpEmuDemoStamp)" Condition="'$(SharpEmuDemoComplete)' == 'true'" />
</ItemGroup>
<RemoveDir
Directories="$(OutDir)$(SharpEmuDemoFolderName)"
Condition="'$(SharpEmuDemoComplete)' != 'true'"
ContinueOnError="WarnAndContinue" />
<Copy
SourceFiles="@(_SharpEmuDemoFiles)"
DestinationFiles="@(_SharpEmuDemoFiles->'$(OutDir)$(SharpEmuDemoFolderName)/%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="true" />
</Target>
<Target Name="PublishSharpEmuDemo" AfterTargets="Publish" DependsOnTargets="FetchSharpEmuDemo">
<ItemGroup>
<_SharpEmuDemoFiles Include="$(SharpEmuDemoDir)**/*" Exclude="$(SharpEmuDemoStamp)" Condition="'$(SharpEmuDemoComplete)' == 'true'" />
</ItemGroup>
<RemoveDir
Directories="$(PublishDir)$(SharpEmuDemoFolderName)"
Condition="'$(SharpEmuDemoComplete)' != 'true'"
ContinueOnError="WarnAndContinue" />
<Copy
SourceFiles="@(_SharpEmuDemoFiles)"
DestinationFiles="@(_SharpEmuDemoFiles->'$(PublishDir)$(SharpEmuDemoFolderName)/%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="true" />
</Target>
</Project>

View File

@ -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"));
}
}

View File

@ -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<GameEntry> games, IReadOnlySet<string> 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));
}
/// <summary>
/// Reads the game title, title id and content version from
/// sce_sys/param.json next to the executable, when present.