Skip to content
Open

dev #430

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: CI

on:
pull_request:
branches: [master, dev, 'v2*']
push:
branches: [master, dev, 'v2*']

env:
DOTNET_VERSION: '8.0.x'
CONFIGURATION: Release

jobs:
build-and-test:
runs-on: windows-latest

env:
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }}
restore-keys: |
${{ runner.os }}-nuget-

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Restore dependencies
run: dotnet restore

- name: Build solution
run: dotnet build "osu!StreamCompanion.sln" --configuration ${{ env.CONFIGURATION }} --no-restore

- name: Run tests
run: dotnet test "osu!StreamCompanion.sln" --configuration ${{ env.CONFIGURATION }} --no-build --verbosity normal

- name: Package portable zips
shell: cmd
run: |
rem rm/cp used by buildRelease-CI.cmd live in Git's usr/bin
set "PATH=C:\Program Files\Git\usr\bin;%PATH%"
buildRelease-CI.cmd zips-only

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: portable-zips
path: |
build/StreamCompanion-portable.zip
build/StreamCompanion-portable-browserOverlay.zip
build/StreamCompanion-portable-textOverlay.zip
107 changes: 107 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Release

on:
push:
tags:
- '**'

env:
DOTNET_VERSION: '8.0.x'
CONFIGURATION: Release

jobs:
build-and-release:
runs-on: windows-latest

env:
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }}
restore-keys: |
${{ runner.os }}-nuget-

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Extract version from tag
id: version
shell: pwsh
run: |
# tag v260724.21 -> AssemblyFileVersion 260724.21
$fileVersion = "${{ github.ref_name }}" -replace '^v', ''
"FILEVERSION=$fileVersion" >> $env:GITHUB_OUTPUT
Write-Host "FileVersion: $fileVersion"

- name: Set assembly file versions from tag
shell: pwsh
run: |
$fileVersion = "${{ steps.version.outputs.FILEVERSION }}"
$files = Get-ChildItem -Recurse -Filter AssemblyInfo.cs
foreach ($file in $files) {
$content = Get-Content $file.FullName -Raw
$patched = $content -replace 'AssemblyFileVersion\(".*?"\)', "AssemblyFileVersion(`"$fileVersion`")"
if ($patched -ne $content) {
Set-Content $file.FullName $patched -NoNewline
Write-Host "patched $($file.FullName)"
}
}

- name: Restore dependencies
run: dotnet restore

- name: Build solution
run: dotnet build "osu!StreamCompanion.sln" --configuration ${{ env.CONFIGURATION }} --no-restore

- name: Run tests
run: dotnet test "osu!StreamCompanion.sln" --configuration ${{ env.CONFIGURATION }} --no-build --verbosity normal

- name: Install InnoSetup
run: choco install innosetup inno-download-plugin -y

- name: Package release files
shell: cmd
env:
FILEVERSION: ${{ steps.version.outputs.FILEVERSION }}
run: |
rem rm/cp used by buildRelease-CI.cmd live in Git's usr/bin
set "PATH=C:\Program Files\Git\usr\bin;%PATH%"
buildRelease-CI.cmd %FILEVERSION%

- name: Collect artifacts
shell: pwsh
run: |
New-Item -ItemType Directory -Path ./artifacts -Force
Move-Item "InnoSetup\Output\StreamCompanion Setup.exe" ./artifacts/
Move-Item "InnoSetup\Output\StreamCompanion-textOverlay.exe" ./artifacts/
Move-Item "InnoSetup\Output\StreamCompanion-browserOverlay.exe" ./artifacts/
Move-Item "build\StreamCompanion-portable.zip" ./artifacts/
Move-Item "build\StreamCompanion-portable-browserOverlay.zip" ./artifacts/
Move-Item "build\StreamCompanion-portable-textOverlay.zip" ./artifacts/
Get-ChildItem ./artifacts

- name: Create draft release
uses: softprops/action-gh-release@v2
with:
draft: true
generate_release_notes: true
# in-app updater matches asset name "StreamCompanion.Setup.exe" (GitHub replaces spaces with dots on upload)
files: |
artifacts/StreamCompanion Setup.exe
artifacts/StreamCompanion-textOverlay.exe
artifacts/StreamCompanion-browserOverlay.exe
artifacts/StreamCompanion-portable.zip
artifacts/StreamCompanion-portable-browserOverlay.zip
artifacts/StreamCompanion-portable-textOverlay.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4 changes: 3 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<!-- <Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" /> -->

<PropertyGroup>
<!-- CS7035: allow yyMMdd.HH AssemblyFileVersion (e.g. 260724.21) matching release tags; -->
<NoWarn>$(NoWarn);CS7035</NoWarn>
<!-- <Nullable>enable</Nullable> -->
</PropertyGroup>
</Project>
</Project>
7 changes: 6 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<PackageReference Include="StreamCompanionTypes" />
</ItemGroup>
<ItemGroup>
<PackageVersion Include="StreamCompanionTypes" version="9.0.0" />
<PackageVersion Include="StreamCompanionTypes" version="9.1.0" />
<PackageVersion Include="CollectionManager" Version="1.0.8" />
<PackageVersion Include="EmbedIO" Version="3.5.2" />
<PackageVersion Include="Fody" Version="6.9.1" />
Expand All @@ -23,7 +23,12 @@
<PackageVersion Include="OsuMemoryDataProvider" Version="0.12.2" />
<PackageVersion Include="PropertyChanged.Fody" Version="3.3.0" />
<PackageVersion Include="ScottPlot.WPF" Version="4.0.48" />
<PackageVersion Include="Serilog" Version="4.4.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="Sentry" Version="6.6.0" />
<PackageVersion Include="Dapper" Version="2.1.35" />
<PackageVersion Include="System.Data.SQLite.Core" Version="1.0.118" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageVersion Include="System.ComponentModel.Composition" Version="5.0.0" />
<PackageVersion Include="System.Data.DataSetExtensions" Version="4.5.0" />
Expand Down
91 changes: 91 additions & 0 deletions PpCalculator/CachedTimedAttributesProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Threading;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using StreamCompanionTypes.Enums;
using StreamCompanionTypes.Interfaces.Services;

namespace PpCalculator
{
public sealed class CachedTimedAttributesProvider : ITimedAttributesProvider, IDisposable
{
public const int DefaultMinimumGenerationMilliseconds = 250;

private readonly int minimumGenerationMilliseconds;

private readonly DifficultyCache cache;
private readonly ITimedAttributesProvider timedAttributesProvider;
private readonly ILogger? logger;

public bool Enabled => cache.Enabled;
public long CacheHits => cache.CacheHits;
public long CacheStores => cache.CacheStores;
public CachedTimedAttributesProvider(string databaseFilePath, int maxCacheEntries, string cacheVersion = DifficultyCache.DefaultCacheVersion,
ILogger? logger = null, ITimedAttributesProvider? timedAttributesProvider = null,
int minimumGenerationMilliseconds = DefaultMinimumGenerationMilliseconds)
{
this.logger = logger;
this.timedAttributesProvider = timedAttributesProvider ?? CalculatingTimedAttributesProvider.Instance;
this.minimumGenerationMilliseconds = minimumGenerationMilliseconds;
cache = new DifficultyCache(databaseFilePath, maxCacheEntries, cacheVersion, logger);
}

public List<TimedDifficultyAttributes> GetTimedAttributes(IWorkingBeatmap workingBeatmap, Ruleset ruleset, IReadOnlyList<Mod> mods, bool isFullBeatmap, CancellationToken cancellationToken)
{
string? beatmapMd5 = workingBeatmap.BeatmapInfo.MD5Hash;
string modsKey = string.Join("|", mods.Select(mod => mod.Acronym));
bool isCachableRequest = isFullBeatmap && cache.Enabled;

if (isCachableRequest && beatmapMd5 != null)
{
try
{
byte[]? blob = cache.TryGetRaw(beatmapMd5, ruleset.RulesetInfo.OnlineID, modsKey);
if (blob != null)
{
logger?.Log($"difficulty cache hit: {beatmapMd5} ruleset {ruleset.RulesetInfo.OnlineID} mods [{modsKey}]", LogLevel.Debug);
return DifficultyCache.Deserialize(blob);
}
}
catch (Exception exception)
{
logger?.Log($"difficulty cache hit failed, computing instead (map {beatmapMd5} ruleset {ruleset.RulesetInfo.OnlineID} mods [{modsKey}])", LogLevel.Warning);
logger?.Log(exception, LogLevel.Warning);
}
}

Stopwatch computeStopwatch = Stopwatch.StartNew();
List<TimedDifficultyAttributes> computed =
timedAttributesProvider.GetTimedAttributes(workingBeatmap, ruleset, mods, isFullBeatmap, cancellationToken);
computeStopwatch.Stop();

if (isCachableRequest && beatmapMd5 != null && computeStopwatch.ElapsedMilliseconds >= minimumGenerationMilliseconds)
{
try
{
byte[] compressedAttributes = DifficultyCache.Serialize(computed);
cache.Store(new DifficultyCache.CacheEntry(
beatmapMd5, ruleset.RulesetInfo.OnlineID, modsKey, compressedAttributes, computeStopwatch.ElapsedMilliseconds));
logger?.Log($"difficulty cache store: {beatmapMd5} ruleset {ruleset.RulesetInfo.OnlineID} mods [{modsKey}] ({compressedAttributes.Length / 1024} KB)", LogLevel.Debug);
}
catch (Exception exception)
{
logger?.Log($"difficulty cache store failed, result unaffected (map {beatmapMd5} ruleset {ruleset.RulesetInfo.OnlineID} mods [{modsKey}])", LogLevel.Warning);
logger?.Log(exception, LogLevel.Warning);
}
}

return computed;
}

internal void FlushPendingEntries() => cache.FlushPendingEntries();

public void Dispose() => cache.Dispose();
}
}
17 changes: 17 additions & 0 deletions PpCalculator/CalculatingTimedAttributesProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Threading;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;

namespace PpCalculator
{
public sealed class CalculatingTimedAttributesProvider : ITimedAttributesProvider
{
public static readonly CalculatingTimedAttributesProvider Instance = new();

public List<TimedDifficultyAttributes> GetTimedAttributes(IWorkingBeatmap workingBeatmap, Ruleset ruleset, IReadOnlyList<Mod> mods, bool isFullBeatmap, CancellationToken cancellationToken)
=> ruleset.CreateDifficultyCalculator(workingBeatmap).CalculateTimed(mods, cancellationToken);
}
}
3 changes: 3 additions & 0 deletions PpCalculator/CtbCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace PpCalculator
public class CtbCalculator : PpCalculator
{
protected override Ruleset Ruleset { get; } = new CatchRuleset();
public CtbCalculator() { }
public CtbCalculator(ITimedAttributesProvider timedAttributesProvider = null) : base(timedAttributesProvider) { }


protected override int GetMaxCombo(IReadOnlyList<HitObject> hitObjects) =>
hitObjects.Count(h => h is Fruit)
Expand Down
Loading
Loading