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
59 changes: 31 additions & 28 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
NDK_HOME="$ANDROID_HOME/ndk/29.0.14206865"
CMAKE_BIN="$ANDROID_HOME/cmake/3.22.1/bin/cmake"

for ABI in arm64-v8a armeabi-v7a; do
for ABI in arm64-v8a armeabi-v7a x86; do
echo "::group::Building osu_native for $ABI"
"$CMAKE_BIN" -B "build-native/$ABI" -S osu.Android/Native \
-DCMAKE_TOOLCHAIN_FILE="$NDK_HOME/build/cmake/android.toolchain.cmake" \
Expand Down Expand Up @@ -91,46 +91,49 @@ jobs:

- name: Build Android APK (signed)
if: steps.keystore.outputs.has_keystore == 'true'
run: >
dotnet publish -c Release
osu.Android/osu.Android.csproj
-f net10.0-android
-p:Version=${{ steps.version.outputs.version }}
-p:ApplicationDisplayVersion=${{ steps.version.outputs.version }}
-p:ApplicationVersion=${{ github.run_number }}
-p:AndroidKeyStore=true
-p:AndroidSigningKeyStore=${{ github.workspace }}/osu.Android/osu.keystore
-p:AndroidSigningKeyAlias=${{ secrets.ANDROID_SIGNING_KEY_ALIAS }}
-p:AndroidSigningKeyPass=${{ secrets.ANDROID_SIGNING_KEY_PASSWORD }}
-p:AndroidSigningStorePass=${{ secrets.ANDROID_SIGNING_STORE_PASSWORD }}
run: |
dotnet publish -c Release \
osu.Android/osu.Android.csproj \
-f net10.0-android \
-p:Version="${{ steps.version.outputs.version }}" \
-p:ApplicationDisplayVersion="${{ steps.version.outputs.version }}" \
-p:ApplicationVersion="${{ github.run_number }}" \
-p:AndroidKeyStore=true \
-p:AndroidSigningKeyStore="${{ github.workspace }}/osu.Android/osu.keystore" \
-p:AndroidSigningKeyAlias="${{ secrets.ANDROID_SIGNING_KEY_ALIAS }}" \
-p:AndroidSigningKeyPass="${{ secrets.ANDROID_SIGNING_KEY_PASSWORD }}" \
-p:AndroidSigningStorePass="${{ secrets.ANDROID_SIGNING_STORE_PASSWORD }}"

- name: Build Android APK (unsigned)
if: steps.keystore.outputs.has_keystore != 'true'
run: >
dotnet publish -c Release
osu.Android/osu.Android.csproj
-f net10.0-android
-p:Version=${{ steps.version.outputs.version }}
-p:ApplicationDisplayVersion=${{ steps.version.outputs.version }}
-p:ApplicationVersion=${{ github.run_number }}
-p:AndroidKeyStore=false
run: |
dotnet publish -c Release \
osu.Android/osu.Android.csproj \
-f net10.0-android \
-p:Version="${{ steps.version.outputs.version }}" \
-p:ApplicationDisplayVersion="${{ steps.version.outputs.version }}" \
-p:ApplicationVersion="${{ github.run_number }}" \
-p:AndroidKeyStore=false

- name: Find APK
id: find_apk
run: |
# The signed/final APK is inside the publish/ directory in net10.0-android
# Strictly prioritize the publish/ directory where the signed APK resides
PUBLISH_DIR="osu.Android/bin/Release/net10.0-android/publish"
echo "Searching for APK in: $PUBLISH_DIR"
APK=$(find "$PUBLISH_DIR" -maxdepth 1 -name "*.apk" 2>/dev/null | head -1)

if [ -z "$APK" ]; then
# Fallback to the parent directory if publish/ doesn't exist for some reason
PUBLISH_DIR="osu.Android/bin/Release/net10.0-android"
APK=$(find "$PUBLISH_DIR" -maxdepth 1 -name "*.apk" 2>/dev/null | head -1)
echo "::warning::Signed APK not found in publish directory. Falling back to bin/Release (MAY BE UNSIGNED!)"
APK=$(find osu.Android/bin/Release -name "*.apk" | head -1)
fi

if [ -z "$APK" ]; then
# Last resort: recursive find
APK=$(find osu.Android/bin/Release -name "*.apk" | head -1)
echo "::error::No APK found anywhere in bin/Release!"
sh -c "false"
fi
echo "Found APK at: $APK"

echo "Final APK found at: $APK"
echo "apk_path=$APK" >> "$GITHUB_OUTPUT"

- name: Upload APK artifact
Expand Down
7 changes: 3 additions & 4 deletions build/PatchElfPageSize.targets
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,10 @@ finally
Patches any 64-bit .so in the NuGet cache that has sub-16 KB LOAD alignment.
The patch is idempotent — already-aligned files are skipped.
-->
<Target Name="PatchAndroidNativeLibPageSize" BeforeTargets="Build">
<Target Name="PatchAndroidNativeLibPageSize" BeforeTargets="Build">
<ItemGroup>
<_NativeLibs Include="$(NuGetPackageRoot)/**/*.so" />
<_NativeLibs Include="$(MSBuildThisFileDirectory)../osu.Android/libs/**/*.so" />
<_NuGetNativeLibs Include="$(NuGetPackageRoot)/**/runtimes/android-*/native/*.so" />
</ItemGroup>
<PatchElfPageSize FilePath="%(Identity)" Condition="'@(_NativeLibs)' != ''" />
<PatchElfPageSize FilePath="%(Identity)" Condition="'@(_NuGetNativeLibs)' != ''" />
</Target>
</Project>
9 changes: 0 additions & 9 deletions debug_ids.py

This file was deleted.

28 changes: 0 additions & 28 deletions final_cleanup.py

This file was deleted.

66 changes: 0 additions & 66 deletions final_cleanup_v2.py

This file was deleted.

65 changes: 39 additions & 26 deletions final_fix.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
import os
import re

def patch_file(path, old, new):
if not os.path.exists(path):
return
def fix_loc():
path = 'osu.Game/Localisation/GraphicsSettingsStrings.cs'
with open(path, 'r') as f:
content = f.read()
if old in content:

# Correct insertion before Resolution
insertion = '\n /// <summary>\n /// "Refresh rate"\n /// </summary>\n public static LocalisableString RefreshRate => new TranslatableString(getKey(@"refresh_rate"), @"Refresh rate");\n'

# We use replace with exact match to ensure indentation is correct (8 spaces)
old_text = ' public static LocalisableString ScreenMode => new TranslatableString(getKey(@"screen_mode"), @"Screen mode");'
new_text = old_text + insertion

if old_text in content and 'RefreshRate' not in content:
with open(path, 'w') as f:
f.write(content.replace(old, new))
else:
# Try regex if literal fails
new_content = re.sub(re.escape(old).replace(r'\ ', r'\s+'), new, content, flags=re.MULTILINE | re.DOTALL)
if new_content != content:
with open(path, 'w') as f:
f.write(new_content)
else:
print(f"Warning: '{old}' not found in {path}")

# 1. Fix GameplayWarmupScreen IDE0074 (compound assignment)
gw_path = 'osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs'
old_gw = """ if (card == null)
{
// Played card was not on the screen.

card = new RankedPlayCard(matchInfo.LastPlayedCard)"""
new_gw = """ card ??= new RankedPlayCard(matchInfo.LastPlayedCard)
{
// Played card was not on the screen."""
# Wait, the braces are different. Let's look at the original code.
f.write(content.replace(old_text, new_text))
print("Fixed Localisation")

def fix_results():
path = 'osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs'
with open(path, 'r') as f:
content = f.read()

# Fix the if-null patterns using regex to preserve indentation exactly
import re

# if (x != null) x.Looping = false; -> x?.Looping = false;
content = re.sub(r'if \((playerScoreTickChannel|opponentScoreTickChannel) != null\) \1\.Looping = false;', r'\1?.Looping = false;', content)

# if (x != null && condition) -> if (condition) \n x?.Looping = false;
# Wait, the original was:
# if (playerScoreTickChannel != null && playerScoreBar.Height >= playerScorePercent)
# playerScoreTickChannel.Looping = false;

content = re.sub(r'if \((playerScoreTickChannel|opponentScoreTickChannel) != null && (.*?)\)\s+(.*?)\.Looping = false;',
r'if (\2)\n \1?.Looping = false;', content)

with open(path, 'w') as f:
f.write(content)
print("Fixed ResultsScreen")

fix_loc()
fix_results()
23 changes: 0 additions & 23 deletions fix_bot_feedback.py

This file was deleted.

54 changes: 0 additions & 54 deletions fix_client_and_tests.py

This file was deleted.

Loading
Loading