diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000000..1a921b21ae
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,87 @@
+name: Pack and nuget
+
+on:
+ push:
+ tags:
+ - '*'
+
+jobs:
+ notify_pending_production_deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Submit pending deployment notification
+ run: |
+ export TITLE="Pending osu Production Deployment: $GITHUB_REF_NAME"
+ export URL="https://github.com/ppy/osu/actions/runs/$GITHUB_RUN_ID"
+ export DESCRIPTION="Awaiting approval for building NuGet packages for tag $GITHUB_REF_NAME:
+ [View Workflow Run]($URL)"
+ export ACTOR_ICON="https://avatars.githubusercontent.com/u/$GITHUB_ACTOR_ID"
+
+ BODY="$(jq --null-input '{
+ "embeds": [
+ {
+ "title": env.TITLE,
+ "color": 15098112,
+ "description": env.DESCRIPTION,
+ "url": env.URL,
+ "author": {
+ "name": env.GITHUB_ACTOR,
+ "icon_url": env.ACTOR_ICON
+ }
+ }
+ ]
+ }')"
+
+ curl \
+ -H "Content-Type: application/json" \
+ -d "$BODY" \
+ "${{ secrets.DISCORD_INFRA_WEBHOOK_URL }}"
+
+ pack:
+ name: Pack
+ runs-on: ubuntu-latest
+ environment: production
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set artifacts directory
+ id: artifactsPath
+ run: echo "::set-output name=nuget_artifacts::${{github.workspace}}/artifacts"
+
+ - name: Install .NET 8.0.x
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: "8.0.x"
+
+ - name: Pack
+ run: |
+ # Replace project references in templates with package reference, because they're included as source files.
+ dotnet remove Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/osu.Game.Rulesets.EmptyFreeform.csproj reference osu.Game/osu.Game.csproj
+ dotnet remove Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj reference osu.Game/osu.Game.csproj
+ dotnet remove Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/osu.Game.Rulesets.EmptyScrolling.csproj reference osu.Game/osu.Game.csproj
+ dotnet remove Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj reference osu.Game/osu.Game.csproj
+
+ dotnet add Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/osu.Game.Rulesets.EmptyFreeform.csproj package ppy.osu.Game -n -v ${{ github.ref_name }}
+ dotnet add Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj package ppy.osu.Game -n -v ${{ github.ref_name }}
+ dotnet add Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/osu.Game.Rulesets.EmptyScrolling.csproj package ppy.osu.Game -n -v ${{ github.ref_name }}
+ dotnet add Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj package ppy.osu.Game -n -v ${{ github.ref_name }}
+
+ # Pack
+ dotnet pack -c Release osu.Game /p:Version=${{ github.ref_name }} /p:GenerateDocumentationFile=true /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg -o ${{steps.artifactsPath.outputs.nuget_artifacts}}
+ dotnet pack -c Release osu.Game.Rulesets.Osu /p:Version=${{ github.ref_name }} /p:GenerateDocumentationFile=true /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg -o ${{steps.artifactsPath.outputs.nuget_artifacts}}
+ dotnet pack -c Release osu.Game.Rulesets.Taiko /p:Version=${{ github.ref_name }} /p:GenerateDocumentationFile=true /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg -o ${{steps.artifactsPath.outputs.nuget_artifacts}}
+ dotnet pack -c Release osu.Game.Rulesets.Catch /p:Version=${{ github.ref_name }} /p:GenerateDocumentationFile=true /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg -o ${{steps.artifactsPath.outputs.nuget_artifacts}}
+ dotnet pack -c Release osu.Game.Rulesets.Mania /p:Version=${{ github.ref_name }} /p:GenerateDocumentationFile=true /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg -o ${{steps.artifactsPath.outputs.nuget_artifacts}}
+ dotnet pack -c Release Templates /p:Version=${{ github.ref_name }} -o ${{steps.artifactsPath.outputs.nuget_artifacts}}
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: osu
+ path: |
+ ${{steps.artifactsPath.outputs.nuget_artifacts}}/*.nupkg
+ ${{steps.artifactsPath.outputs.nuget_artifacts}}/*.snupkg
+
+ - name: Publish packages to nuget.org
+ run: dotnet nuget push ${{steps.artifactsPath.outputs.nuget_artifacts}}/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Replays/EmptyFreeformReplayFrame.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Replays/EmptyFreeformReplayFrame.cs
index c84101ca70..c6be5d6861 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Replays/EmptyFreeformReplayFrame.cs
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Replays/EmptyFreeformReplayFrame.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Linq;
using osu.Game.Rulesets.Replays;
using osuTK;
@@ -17,5 +18,8 @@ namespace osu.Game.Rulesets.EmptyFreeform.Replays
if (button.HasValue)
Actions.Add(button.Value);
}
+
+ public override bool IsEquivalentTo(ReplayFrame other)
+ => other is EmptyFreeformReplayFrame freeformFrame && Time == freeformFrame.Time && Position == freeformFrame.Position && Actions.SequenceEqual(freeformFrame.Actions);
}
}
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Replays/PippidonReplayFrame.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Replays/PippidonReplayFrame.cs
index 949ca160be..c434b62257 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Replays/PippidonReplayFrame.cs
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Replays/PippidonReplayFrame.cs
@@ -9,5 +9,8 @@ namespace osu.Game.Rulesets.Pippidon.Replays
public class PippidonReplayFrame : ReplayFrame
{
public Vector2 Position;
+
+ public override bool IsEquivalentTo(ReplayFrame other)
+ => other is PippidonReplayFrame pippidonFrame && Time == pippidonFrame.Time && Position == pippidonFrame.Position;
}
}
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Replays/EmptyScrollingReplayFrame.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Replays/EmptyScrollingReplayFrame.cs
index 2f19cffd2a..722eff6f05 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Replays/EmptyScrollingReplayFrame.cs
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Replays/EmptyScrollingReplayFrame.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Linq;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.EmptyScrolling.Replays
@@ -15,5 +16,8 @@ namespace osu.Game.Rulesets.EmptyScrolling.Replays
if (button.HasValue)
Actions.Add(button.Value);
}
+
+ public override bool IsEquivalentTo(ReplayFrame other)
+ => other is EmptyScrollingReplayFrame scrollingFrame && Time == scrollingFrame.Time && Actions.SequenceEqual(scrollingFrame.Actions);
}
}
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Replays/PippidonReplayFrame.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Replays/PippidonReplayFrame.cs
index 468ac9c725..c8df06f6d7 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Replays/PippidonReplayFrame.cs
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Replays/PippidonReplayFrame.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Linq;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Pippidon.Replays
@@ -15,5 +16,8 @@ namespace osu.Game.Rulesets.Pippidon.Replays
if (button.HasValue)
Actions.Add(button.Value);
}
+
+ public override bool IsEquivalentTo(ReplayFrame other)
+ => other is PippidonReplayFrame pippidonFrame && Time == pippidonFrame.Time && Actions.SequenceEqual(pippidonFrame.Actions);
}
}
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index ed48a997e8..0000000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-clone_depth: 1
-version: '{branch}-{build}'
-image: Visual Studio 2022
-cache:
- - '%LOCALAPPDATA%\NuGet\v3-cache -> appveyor.yml'
-
-dotnet_csproj:
- patch: true
- file: 'osu.Game\osu.Game.csproj' # Use wildcard when it's able to exclude Xamarin projects
- version: '0.0.{build}'
-
-before_build:
- - cmd: dotnet --info # Useful when version mismatch between CI and local
- - cmd: dotnet workload install maui-android # Change to `dotnet workload restore` once there's no old projects
- - cmd: dotnet workload install maui-ios # Change to `dotnet workload restore` once there's no old projects
- - cmd: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects
-
-build:
- project: osu.sln
- parallel: true
- verbosity: minimal
- publish_nuget: true
-
-after_build:
- - ps: .\InspectCode.ps1
-
-test:
- assemblies:
- except:
- - '**\*Android*'
- - '**\*iOS*'
- - 'build\**\*'
diff --git a/appveyor_deploy.yml b/appveyor_deploy.yml
deleted file mode 100644
index 175c8d0f1b..0000000000
--- a/appveyor_deploy.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-clone_depth: 1
-version: '{build}'
-image: Visual Studio 2022
-test: off
-skip_non_tags: true
-configuration: Release
-
-environment:
- matrix:
- - job_name: osu-game
- - job_name: osu-ruleset
- job_depends_on: osu-game
- - job_name: taiko-ruleset
- job_depends_on: osu-game
- - job_name: catch-ruleset
- job_depends_on: osu-game
- - job_name: mania-ruleset
- job_depends_on: osu-game
- - job_name: templates
- job_depends_on: osu-game
-
-nuget:
- project_feed: true
-
-for:
- -
- matrix:
- only:
- - job_name: osu-game
- build_script:
- - cmd: dotnet pack osu.Game\osu.Game.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
- -
- matrix:
- only:
- - job_name: osu-ruleset
- build_script:
- - cmd: dotnet remove osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj reference osu.Game\osu.Game.csproj
- - cmd: dotnet add osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- - cmd: dotnet pack osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
- -
- matrix:
- only:
- - job_name: taiko-ruleset
- build_script:
- - cmd: dotnet remove osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj reference osu.Game\osu.Game.csproj
- - cmd: dotnet add osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- - cmd: dotnet pack osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
- -
- matrix:
- only:
- - job_name: catch-ruleset
- build_script:
- - cmd: dotnet remove osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj reference osu.Game\osu.Game.csproj
- - cmd: dotnet add osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- - cmd: dotnet pack osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
- -
- matrix:
- only:
- - job_name: mania-ruleset
- build_script:
- - cmd: dotnet remove osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj reference osu.Game\osu.Game.csproj
- - cmd: dotnet add osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- - cmd: dotnet pack osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
- -
- matrix:
- only:
- - job_name: templates
- build_script:
- - cmd: dotnet remove Templates\Rulesets\ruleset-empty\osu.Game.Rulesets.EmptyFreeform\osu.Game.Rulesets.EmptyFreeform.csproj reference osu.Game\osu.Game.csproj
- - cmd: dotnet remove Templates\Rulesets\ruleset-example\osu.Game.Rulesets.Pippidon\osu.Game.Rulesets.Pippidon.csproj reference osu.Game\osu.Game.csproj
- - cmd: dotnet remove Templates\Rulesets\ruleset-scrolling-empty\osu.Game.Rulesets.EmptyScrolling\osu.Game.Rulesets.EmptyScrolling.csproj reference osu.Game\osu.Game.csproj
- - cmd: dotnet remove Templates\Rulesets\ruleset-scrolling-example\osu.Game.Rulesets.Pippidon\osu.Game.Rulesets.Pippidon.csproj reference osu.Game\osu.Game.csproj
-
- - cmd: dotnet add Templates\Rulesets\ruleset-empty\osu.Game.Rulesets.EmptyFreeform\osu.Game.Rulesets.EmptyFreeform.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- - cmd: dotnet add Templates\Rulesets\ruleset-example\osu.Game.Rulesets.Pippidon\osu.Game.Rulesets.Pippidon.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- - cmd: dotnet add Templates\Rulesets\ruleset-scrolling-empty\osu.Game.Rulesets.EmptyScrolling\osu.Game.Rulesets.EmptyScrolling.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- - cmd: dotnet add Templates\Rulesets\ruleset-scrolling-example\osu.Game.Rulesets.Pippidon\osu.Game.Rulesets.Pippidon.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
-
- - cmd: dotnet pack Templates\osu.Game.Templates.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
-
-artifacts:
- - path: '**\*.nupkg'
-
-deploy:
- - provider: Environment
- name: nuget
diff --git a/osu.Android.props b/osu.Android.props
index 92e3312fd8..de3fe31ee6 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -10,7 +10,7 @@
true
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 205e85ba51..bb5e3da49e 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -17,6 +17,6 @@
-all
-
+