Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ jobs:
- name: Build Android APK (signed)
if: steps.keystore.outputs.has_keystore == 'true'
run: >
dotnet publish -c Release
dotnet publish -c Release -p:PublishTrimmed=false -p:AndroidLinkMode=None
osu.Android/osu.Android.csproj
-f net10.0-android
-p:Version=${{ steps.version.outputs.version }}
Expand All @@ -104,7 +104,7 @@ jobs:
- name: Build Android APK (unsigned)
if: steps.keystore.outputs.has_keystore != 'true'
run: >
dotnet publish -c Release
dotnet publish -c Release -p:PublishTrimmed=false -p:AndroidLinkMode=None
osu.Android/osu.Android.csproj
-f net10.0-android
-p:Version=${{ steps.version.outputs.version }}
Expand Down
44 changes: 0 additions & 44 deletions final_fix.py

This file was deleted.

14 changes: 13 additions & 1 deletion osu.Android.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<SupportedOSPlatformVersion>33.0</SupportedOSPlatformVersion>
<RuntimeIdentifiers>android-x86;android-arm;android-arm64</RuntimeIdentifiers>
<AndroidPackageFormat>apk</AndroidPackageFormat>
<MandroidI18n>CJK;Mideast;Rare;West;Other;</MandroidI18n>
<MandroidI18n>CJK;West;</MandroidI18n>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidMessageHandler</AndroidHttpClientHandlerType>
<!-- NullabilityInfoContextSupport is disabled by default for Android -->
<NullabilityInfoContextSupport>true</NullabilityInfoContextSupport>
Expand All @@ -24,6 +24,9 @@
<RunAOTCompilation>true</RunAOTCompilation>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
<PublishTrimmed>false</PublishTrimmed>
<AndroidLinkMode>None</AndroidLinkMode>
<AndroidEnableResourceShrinking>false</AndroidEnableResourceShrinking>
</PropertyGroup>
<ItemGroup>
<!-- IMPORTANT: ppy.osu.Framework.Android v2026.318.0 only ships net8.0-android34.0 assets.
Expand All @@ -38,4 +41,13 @@
Since Realm objects are not declared directly in Android projects, simply disable Fody. -->
<DisableFody>true</DisableFody>
</PropertyGroup>

<!-- Fix for .NET 10 Android AOT misclassifying non-managed assets in runtime pack -->
<Target Name="FixRuntimePackAssetTypes" AfterTargets="ResolveRuntimePackAssets">
<ItemGroup>
<RuntimePackAsset Update="@(RuntimePackAsset)" Condition="'%(Extension)' != '.dll'">
<AssetType>native</AssetType>
</RuntimePackAsset>
</ItemGroup>
</Target>
</Project>
6 changes: 3 additions & 3 deletions osu.Desktop/LegacyIpc/LegacyIpcMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ namespace osu.Desktop.LegacyIpc
/// In order to deserialise types at either end, types must be serialised as their <see cref="System.Type.AssemblyQualifiedName"/>,
/// however this cannot be done since osu!stable and osu!lazer live in two different assemblies.
/// <br />
/// To get around this, this class exists which serialises a payload (<see cref="LegacyIpcMessage.Data"/>) as an <see cref="System.Object"/> type,
/// To get around this, this class exists which serialises a payload (<see cref="Data"/>) as an <see cref="System.Object"/> type,
/// which can be deserialised at either end because it is part of the core library (mscorlib / System.Private.CorLib).
/// The payload contains the data to be sent over the IPC channel.
/// <br />
/// At either end, Json.NET deserialises the payload into a <see cref="JObject"/> which is manually converted back into the expected <see cref="LegacyIpcMessage.Data"/> type,
/// At either end, Json.NET deserialises the payload into a <see cref="JObject"/> which is manually converted back into the expected <see cref="Data"/> type,
/// which then further contains another <see cref="JObject"/> representing the data sent over the IPC channel whose type can likewise be lazily matched through
/// <see cref="LegacyIpcMessage.Data.MessageType"/>.
/// <see cref="Data.MessageType"/>.
/// </para>
/// </summary>
/// <remarks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected override void OnFree()
MissingStartTime.UnbindFrom(parentHold.MissingStartTime);
}

public bool UpdateResult() => base.UpdateResult(true);
public bool UpdateResult() => UpdateResult(true);

protected override void UpdateHitStateTransforms(ArmedState state)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ protected override void OnFree()
MissingStartTime.UnbindFrom(parentHold.MissingStartTime);
}

public void UpdateResult() => base.UpdateResult(true);
public void UpdateResult() => UpdateResult(true);

protected override void CheckForResult(bool userTriggered, double timeOffset) =>
// Factor in the release lenience
Expand Down
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Mania/Objects/HoldNote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ protected override void CreateNestedHitObjects(CancellationToken cancellationTok
/// By default, osu!mania beatmaps in only play samples at the start of the hold note.
/// </remarks>
/// <param name="obj">The object to use as a basis for the head sample.</param>
/// <returns>Defaults for assigning to <see cref="HoldNote.NodeSamples"/>.</returns>
/// <returns>Defaults for assigning to <see cref="NodeSamples"/>.</returns>
public static List<IList<HitSampleInfo>> CreateDefaultNodeSamples(HitObject obj) => new List<IList<HitSampleInfo>>
{
obj.Samples,
Expand Down
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
namespace osu.Game.Rulesets.Mania.UI
{
/// <summary>
/// A <see cref="Framework.Graphics.Containers.Container"/> that has its contents partially hidden by an adjustable "cover". This is intended to be used in a playfield.
/// A <see cref="Container"/> that has its contents partially hidden by an adjustable "cover". This is intended to be used in a playfield.
/// </summary>
public partial class PlayfieldCoveringWrapper : CompositeDrawable
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
#nullable disable

using System.Collections.Generic;

using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics;

using osu.Game.Rulesets.Objects.Pooling;
using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Pooling;

namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{
Expand Down Expand Up @@ -148,4 +146,4 @@ protected override void Dispose(bool isDisposing)
lifetimeEntries.Clear();
}
}
}
}
13 changes: 5 additions & 8 deletions osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@

#nullable disable

using System.Collections.Generic;
using System;

using System.Collections.Generic;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;

using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Skinning;

using JetBrains.Annotations;
using osuTK.Graphics;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Expand Down Expand Up @@ -209,4 +206,4 @@ internal void RestoreHitAnimations()

#endregion
}
}
}
10 changes: 7 additions & 3 deletions osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public void TestDailyChallenge()
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
],
StartDate = DateTimeOffset.Now.AddSeconds(-10),
EndDate = DateTimeOffset.Now.AddHours(12),
Category = RoomCategory.DailyChallenge
};
Expand All @@ -74,6 +75,7 @@ public void TestUseTheseModsUnavailableIfNoFreeMods()
AllowedMods = []
}
],
StartDate = DateTimeOffset.Now.AddSeconds(-10),
EndDate = DateTimeOffset.Now.AddHours(12),
Category = RoomCategory.DailyChallenge
};
Expand Down Expand Up @@ -106,18 +108,19 @@ public void TestNotifications()
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
],
StartDate = DateTimeOffset.Now.AddSeconds(-10),
EndDate = DateTimeOffset.Now.AddHours(12),
Category = RoomCategory.DailyChallenge
};

AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = room.RoomID!.Value });
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = (room.RoomID ?? 0) });

Screens.OnlinePlay.DailyChallenge.DailyChallenge screen = null!;
AddStep("push screen", () => LoadScreen(screen = new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
AddUntilStep("wait for screen", () => screen.IsCurrentScreen());
AddStep("daily challenge ended", () => metadataClient.DailyChallengeInfo.Value = null);
AddAssert("notification posted", () => notificationOverlay.AllNotifications.OfType<SimpleNotification>().Any(n => n.Text == DailyChallengeStrings.ChallengeEndedNotification));
AddUntilStep("notification posted", () => notificationOverlay.AllNotifications.OfType<SimpleNotification>().Any(n => n.Text == DailyChallengeStrings.ChallengeEndedNotification));
}

[Test]
Expand All @@ -134,12 +137,13 @@ public void TestConclusionNotificationDoesNotFireOnDisconnect()
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
],
StartDate = DateTimeOffset.Now.AddSeconds(-10),
EndDate = DateTimeOffset.Now.AddHours(12),
Category = RoomCategory.DailyChallenge
};

AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = room.RoomID!.Value });
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = (room.RoomID ?? 0) });

Screens.OnlinePlay.DailyChallenge.DailyChallenge screen = null!;
AddStep("push screen", () => LoadScreen(screen = new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Online.API;
using osu.Game.Online.Metadata;
Expand All @@ -17,7 +19,6 @@
using osu.Game.Tests.Visual.OnlinePlay;
using osuTK.Graphics;
using osuTK.Input;
using CreateRoomRequest = osu.Game.Online.Rooms.CreateRoomRequest;

namespace osu.Game.Tests.Visual.DailyChallenge
{
Expand All @@ -29,7 +30,7 @@
[Cached(typeof(INotificationOverlay))]
private NotificationOverlay notificationOverlay = new NotificationOverlay();

private Room room = null!;
private Room? room;

[BackgroundDependencyLoader]
private void load()
Expand All @@ -44,31 +45,53 @@
[Test]
public void TestDailyChallenge()
{
startChallenge();
AddStep("push screen", () => LoadScreen(new DailyChallengeIntro(room)));
startChallenge("first");
AddUntilStep("wait for button room", () => this.ChildrenOfType<DailyChallengeButton>().FirstOrDefault()?.Room?.RoomID == room?.RoomID);
AddStep("push screen", () =>
{
if (room != null)
LoadScreen(new DailyChallengeIntro(room));
});
}

[Test]
public void TestPlayIntroOnceFlag()
{
startChallenge();
startChallenge("first");
AddUntilStep("wait for first button room", () =>
{
var btn = this.ChildrenOfType<DailyChallengeButton>().FirstOrDefault();
return btn != null && btn.Room != null && btn.Room.RoomID == room?.RoomID;
});

AddStep("set intro played flag", () => Dependencies.Get<SessionStatics>().SetValue(Static.DailyChallengeIntroPlayed, true));
AddAssert("intro played flag is true", () => Dependencies.Get<SessionStatics>().Get<bool>(Static.DailyChallengeIntroPlayed));

startChallenge();
startChallenge("second");

AddAssert("intro played flag reset", () => Dependencies.Get<SessionStatics>().Get<bool>(Static.DailyChallengeIntroPlayed), () => Is.False);
AddUntilStep("wait for button to update to second room", () =>
{
var btn = this.ChildrenOfType<DailyChallengeButton>().FirstOrDefault();
return btn != null && btn.Room != null && btn.Room.RoomID == room?.RoomID;
});
AddUntilStep("intro played flag reset", () => !Dependencies.Get<SessionStatics>().Get<bool>(Static.DailyChallengeIntroPlayed));

AddStep("push screen", () => LoadScreen(new DailyChallengeIntro(room)));
AddUntilStep("intro played flag set", () => Dependencies.Get<SessionStatics>().Get<bool>(Static.DailyChallengeIntroPlayed), () => Is.True);
AddStep("push screen", () =>
{
if (room != null)
LoadScreen(new DailyChallengeIntro(room));
});
}

private void startChallenge()
private void startChallenge(string suffix)
{
AddStep("add room", () =>
AddStep($"reset info ({suffix})", () => metadataClient.DailyChallengeUpdated(null!));
AddStep($"reset room ({suffix})", () => room = null);
AddStep($"add room ({suffix})", () =>
{
API.Perform(new CreateRoomRequest(room = new Room
var newRoom = new Room
{
Name = "Daily Challenge: June 4, 2024",
Name = $"Daily Challenge {suffix}",
Playlist =
[
new PlaylistItem(CreateAPIBeatmap(new OsuRuleset().RulesetInfo))
Expand All @@ -77,12 +100,20 @@
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
],
StartDate = DateTimeOffset.Now,
StartDate = DateTimeOffset.Now.AddSeconds(-10),
EndDate = DateTimeOffset.Now.AddHours(24),
Category = RoomCategory.DailyChallenge
}));
};
room = newRoom;
API.Perform(new CreateRoomRequest(newRoom));
});
AddUntilStep($"wait for room id ({suffix})", () => room?.RoomID != null && room.RoomID > 0);
AddUntilStep($"wait for playlist id ({suffix})", () => room != null && room.Playlist.All(p => p.ID > 0));
AddStep($"signal client ({suffix})", () =>
{
if (room != null && room.RoomID.HasValue)
metadataClient.DailyChallengeUpdated(new DailyChallengeInfo { RoomID = room.RoomID.Value });
});
AddStep("signal client", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo { RoomID = room.RoomID!.Value }));
}
}
}
2 changes: 1 addition & 1 deletion osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ private void load()
}

/// <summary>
/// Mutable dummy BatteryInfo class for <see cref="TestScenePlayerLoader.TestLowBatteryNotification"/>
/// Mutable dummy BatteryInfo class for <see cref="TestLowBatteryNotification"/>
/// </summary>
/// <inheritdoc/>
private class LocalBatteryInfo : BatteryInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ public void TestSelectionNotLostWithConvertedBeatmapsShown()
/// <summary>
/// Note: This test was written to demonstrate the failure described at https://github.com/ppy/osu/issues/35023,
/// but because the failure scenario there entailed a race condition, it was possible for the test to pass regardless
/// unless <see cref="osu.Game.Screens.Select.SongSelect.SELECTION_DEBOUNCE"/> was increased.
/// unless <see cref="Screens.Select.SongSelect.SELECTION_DEBOUNCE"/> was increased.
/// </summary>
[Test]
public void TestPresentFromResults()
Expand Down
Loading
Loading