Skip to content
51 changes: 51 additions & 0 deletions check_for_result_optimized.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (userTriggered || !TailCircle.Judged || Time.Current < HitObject.EndTime)
return;

if (HitObject.ClassicSliderBehaviour)
{
// Classic behaviour means a slider is judged proportionally to the number of nested hitobjects hit. This is the classic osu!stable scoring.
ApplyResult(static (r, hitObject) =>
{
int totalTicks = hitObject.NestedHitObjects.Count;
int hitTicks = 0;

for (int i = 0; i < totalTicks; i++)
{
if (hitObject.NestedHitObjects[i].IsHit)
hitTicks++;
}

if (hitTicks == totalTicks)
r.Type = HitResult.Great;
else if (hitTicks == 0)
r.Type = HitResult.Miss;
else
{
double hitFraction = (double)hitTicks / totalTicks;
r.Type = hitFraction >= 0.5 ? HitResult.Ok : HitResult.Meh;
}
});
}
else
{
// If only the nested hitobjects are judged, then the slider's own judgement is ignored for scoring purposes.
// But the slider needs to still be judged with a reasonable hit/miss result for visual purposes (hit/miss transforms, etc).
ApplyResult(static (r, hitObject) =>
{
bool anyHit = false;

for (int i = 0; i < hitObject.NestedHitObjects.Count; i++)
{
if (hitObject.NestedHitObjects[i].Result.IsHit)
{
anyHit = true;
break;
}
}

r.Type = anyHit ? r.Judgement.MaxResult : r.Judgement.MinResult;
});
}
}
35 changes: 35 additions & 0 deletions dho_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import sys

with open('osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs', 'r') as f:
lines = f.readlines()

# Add using osu.Framework;
if 'using osu.Framework;\n' not in lines:
lines.insert(3, 'using osu.Framework;\n')

for i, line in enumerate(lines):
if 'protected override void Update()' in line:
start_idx = i
# Find the end of the method
method_end_idx = i
while '}' not in lines[method_end_idx]:
method_end_idx += 1
method_end_idx += 1

# We add an early out for Android
optimized_code = [
" protected override void Update()\n",
" {\n",
" if (RuntimeInfo.IsAndroid && (Time.Current < LifetimeStart - 1000 || Time.Current > LifetimeEnd))\n",
" return;\n",
"\n"
]

# Keep the rest of the original Update body
original_body = lines[start_idx+2:method_end_idx]

lines[start_idx:method_end_idx] = optimized_code + original_body
break

with open('osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs', 'w') as f:
f.writelines(lines)
30 changes: 30 additions & 0 deletions final_fixes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import sys

# 1. Fix DrawableSlider.cs (Add .ToArray())
with open('osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs', 'r') as f:
lines = f.readlines()

for i, line in enumerate(lines):
if 'Samples.Samples = HitObject.TailSamples;' in line:
lines[i] = " Samples.Samples = HitObject.TailSamples.ToArray();\n"
if 'slidingSample.Samples = HitObject.CreateSlidingSamples();' in line:
lines[i] = " slidingSample.Samples = HitObject.CreateSlidingSamples().ToArray();\n"

with open('osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs', 'w') as f:
f.writelines(lines)

# 2. Fix SnakingSliderBody.cs (Use a double-based frame count or just a local counter)
with open('osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs', 'r') as f:
lines = f.readlines()

# Replace lastUpdateFrame with a double and use Clock.CurrentTime
for i, line in enumerate(lines):
if 'private ulong lastUpdateFrame;' in line:
lines[i] = " private double lastUpdateTime;\n"
if 'if (lastUpdateFrame > 0 && Clock.CurrentFrame - lastUpdateFrame < 2)' in line:
lines[i] = " if (lastUpdateTime > 0 && Clock.CurrentTime - lastUpdateTime < 16)\n"
if 'lastUpdateFrame = Clock.CurrentFrame;' in line:
lines[i] = " lastUpdateTime = Clock.CurrentTime;\n"

with open('osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs', 'w') as f:
f.writelines(lines)
89 changes: 89 additions & 0 deletions fix_all_headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import os

files = [
'osu.Game/Rulesets/Objects/SliderPath.cs',
'osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs',
'osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs',
'osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs',
'osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs',
'osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs',
'osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs'
]

HEADER_LINES = [
"// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.",
"// See the LICENCE file in the repository root for full licence text."
]

def fix_file(path):
with open(path, 'rb') as f:
content = f.read()

# Remove BOM if present
if content.startswith(b'\xef\xbb\xbf'):
content = content[3:]

text = content.decode('utf-8')
lines = text.splitlines()

# 1. Strip all copyright header and using lines, and nullable disable
clean_lines = []
usings = []
nullable_line = None

for line in lines:
stripped = line.strip()
if stripped in HEADER_LINES:
continue
if stripped.startswith('using '):
if stripped.endswith(';'):
usings.append(stripped)
continue
if stripped == '#nullable disable':
nullable_line = stripped
continue
clean_lines.append(line)

# 2. Strip leading/trailing empty lines from body
while clean_lines and not clean_lines[0].strip():
clean_lines.pop(0)
while clean_lines and not clean_lines[-1].strip():
clean_lines.pop()

# 3. Deduplicate and sort usings
# Group them: System first, then osu.Framework, then osu.Game, then others
usings = sorted(list(set(usings)))

system_usings = [u for u in usings if u.startswith('using System')]
framework_usings = [u for u in usings if u.startswith('using osu.Framework')]
game_usings = [u for u in usings if u.startswith('using osu.Game')]
other_usings = [u for u in usings if u not in system_usings and u not in framework_usings and u not in game_usings]

sorted_usings = []
if system_usings: sorted_usings.extend(system_usings + [""])
if framework_usings: sorted_usings.extend(framework_usings + [""])
if game_usings: sorted_usings.extend(game_usings + [""])
if other_usings: sorted_usings.extend(other_usings + [""])

# 4. Construct final content
final_lines = HEADER_LINES + [""]
if nullable_line:
final_lines.extend([nullable_line, ""])

final_lines.extend(sorted_usings)
final_lines.extend(clean_lines)
final_lines.append("") # End with newline

final_text = "\r\n".join(final_lines)

# 5. Write back with BOM
with open(path, 'wb') as f:
f.write(b'\xef\xbb\xbf')
f.write(final_text.encode('utf-8'))

for f in files:
if os.path.exists(f):
fix_file(f)
print(f"Fixed {f}")
else:
print(f"Skipped {f} (not found)")
90 changes: 90 additions & 0 deletions fix_all_headers_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import os

files = [
'osu.Game/Rulesets/Objects/SliderPath.cs',
'osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs',
'osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs',
'osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs',
'osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs',
'osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs',
'osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs'
]

HEADER_LINES = [
"// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.",
"// See the LICENCE file in the repository root for full licence text."
]

def fix_file(path):
with open(path, 'rb') as f:
content = f.read()

# Remove BOM if present
if content.startswith(b'\xef\xbb\xbf'):
content = content[3:]

text = content.decode('utf-8')
lines = text.splitlines()

# 1. Extract clean body and usings
clean_body = []
usings = []
nullable_line = None

for line in lines:
stripped = line.strip()
# Skip existing header lines
if stripped in HEADER_LINES:
continue
# Skip existing BOM markers if they leaked into lines
if stripped.startswith('\ufeff'):
continue

if stripped.startswith('using '):
if stripped.endswith(';'):
usings.append(stripped)
continue
if stripped == '#nullable disable':
nullable_line = stripped
continue
# If we hit the namespace or class, stop collecting usings and take the rest as body
if stripped.startswith('namespace ') or stripped.startswith('public ') or stripped.startswith('internal ') or stripped.startswith('private '):
idx = lines.index(line)
clean_body = lines[idx:]
break

# 2. Deduplicate and sort usings
usings = sorted(list(set(usings)))

# 3. Construct final content
final_lines = []
final_lines.extend(HEADER_LINES)
final_lines.append("")

if nullable_line:
final_lines.append(nullable_line)
final_lines.append("")

if usings:
final_lines.extend(usings)
final_lines.append("")

# Trim leading/trailing whitespace from body
while clean_body and not clean_body[0].strip():
clean_body.pop(0)
while clean_body and not clean_body[-1].strip():
clean_body.pop()

final_lines.extend(clean_body)
final_lines.append("") # Final newline

final_text = "\r\n".join(final_lines)

with open(path, 'wb') as f:
f.write(b'\xef\xbb\xbf')
f.write(final_text.encode('utf-8'))

for f in files:
if os.path.exists(f):
fix_file(f)
print(f"Fixed {f}")
32 changes: 32 additions & 0 deletions fix_final_formatting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os

path = 'osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs'

with open(path, 'rb') as f:
content = f.read()

has_bom = content.startswith(b'\xef\xbb\xbf')
if has_bom:
content = content[3:]

text = content.decode('utf-8')
lines = text.splitlines()

new_lines = []
for line in lines:
stripped = line.strip()
# Correcting indentation for the specific method calls in UpdateState
if stripped in ["UpdateInitialTransforms();", "UpdateStartTimeStateTransforms();", "UpdateHitStateTransforms(newState);"]:
# The previous attempt used 16 spaces (4 tabs-worth), but looking at the surrounding context:
# UpdateState is indented with 2 tabs (8 spaces).
# Inside the method is 3 tabs (12 spaces).
# It looks like my previous script added too many spaces or miscounted.
new_lines.append(" " + stripped) # 12 spaces
else:
new_lines.append(line)

final_text = "\r\n".join(new_lines)
with open(path, 'wb') as f:
if has_bom:
f.write(b'\xef\xbb\xbf')
f.write(final_text.encode('utf-8'))
Loading
Loading