Skip to content

Commit

Permalink
it works i love it
Browse files Browse the repository at this point in the history
  • Loading branch information
rushiiMachine committed Mar 28, 2024
1 parent fa4976c commit b792aa4
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 40 deletions.
53 changes: 40 additions & 13 deletions Osu.Patcher.Hook/Patches/LivePerformance/PatchAddPerformanceToUi.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using HarmonyLib;
using JetBrains.Annotations;
Expand All @@ -10,6 +11,7 @@ namespace Osu.Patcher.Hook.Patches.LivePerformance;
/// <summary>
/// Hooks the constructor of <c>ScoreDisplay</c> to add our own <c>pTextSprite</c> for displaying
/// the performance counter to the ScoreDisplay's sprite manager.
/// This needs [email protected] or score-p.png in your skin's score font assets!
/// </summary>
[HarmonyPatch]
[UsedImplicitly]
Expand All @@ -27,32 +29,39 @@ private static void After(
[HarmonyArgument(0)] object spriteManager, // SpriteManager
[HarmonyArgument(1)] object position, // Vector2
[HarmonyArgument(2)] bool alignRight,
[HarmonyArgument(3)] float scale,
[HarmonyArgument(4)] bool showScore,
[HarmonyArgument(5)] bool showAccuracy
[HarmonyArgument(3)] float scale
)
{
var positionX = Vector2.X.Get(position);

// TODO: use correct position
var startPosition = ((ConstructorInfo)Vector2.Constructor.Reference).Invoke([positionX, 0f]);
var currentSkin = SkinManager.Current.Get();
var scoreFont = SkinOsu.FontScore.Get(currentSkin);
var scoreFontOverlap = SkinOsu.FontScoreOverlap.Get(currentSkin);

var performanceSprite = ((ConstructorInfo)pSpriteText.Constructor.Reference).Invoke(
[
/* text: */ "0000.0",
/* fontName: */ "Assets/score/score",
/* spacingOverlap: */ 10f,
/* text: */ "00.0pp",
/* fontName: */ scoreFont,
/* spacingOverlap: */ (float)scoreFontOverlap,
/* fieldType: */ alignRight ? Fields.TopRight : Fields.TopLeft,
/* origin: */ alignRight ? Origins.TopRight : Origins.TopLeft,
/* clock: */ Clocks.Game,
/* startPosition: */ startPosition,
/* startPosition: */ ((ConstructorInfo)Vector2.Constructor.Reference).Invoke([0f, 0f]),
/* drawDepth: */ 0.95f,
/* alwaysDraw: */ true,
/* color: */ Color.White, // TODO: try GhostWhite
/* color: */ Color.White,
/* precache: */ true,
/* source: */ SkinSource.All,
/* source: */ SkinSource.ExceptBeatmap,
]);

// Cannot be startPosition directly
var positionX = Vector2.X.Get(position) + 8f;
var positionY = GetYOffset(Vector2.Y.Get(position), scale, __instance);
var newPosition = ((ConstructorInfo)Vector2.Constructor.Reference).Invoke([positionX, positionY]);
pDrawable.Position.Set(performanceSprite, newPosition);

pDrawable.Scale.Set(performanceSprite, 0.50f);
pSpriteText.TextConstantSpacing.Set(performanceSprite, true);
pSpriteText.MeasureText.Invoke(performanceSprite);

SpriteManager.Add.Invoke(spriteManager, [performanceSprite]);
PerformanceDisplay.SetPerformanceCounter(performanceSprite);
}
Expand All @@ -67,4 +76,22 @@ private static void Finalizer(Exception? __exception)
Console.WriteLine($"Exception due to {nameof(PatchAddPerformanceToScoreDisplay)}: {__exception}");
}
}

private static float GetYOffset(float baseYPosition, float scale, object scoreDisplay)
{
// Read the heights of both pSpriteTexts: s_Score, s_Accuracy
var sprites = ScoreDisplay.RuntimeType
.GetDeclaredFields()
.Where(f => f.FieldType == pSpriteText.RuntimeType)
.Select(f => f.GetValue(scoreDisplay));
var spriteSizes = sprites
.Where(s => s != null)
.Select(s => pSpriteText.MeasureText.Invoke(s));
var totalSpriteHeight = spriteSizes.Sum(v => Vector2.Y.Get(v)) * 0.58f * scale;

// Preserve additional spacing between s_Score and s_Accuracy
var additionalOffset = SkinManager.GetUseNewLayout.Invoke() ? 3f : 0f;

return baseYPosition + totalSpriteHeight + additionalOffset;
}
}
28 changes: 2 additions & 26 deletions Osu.Patcher.Hook/Patches/LivePerformance/PerformanceDisplay.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Reflection;
using HarmonyLib;
using Osu.Stubs;

namespace Osu.Patcher.Hook.Patches.LivePerformance;
Expand Down Expand Up @@ -31,7 +29,7 @@ public static void UpdatePerformanceCounter(double pp)
var scoreDisplay = Ruleset.ScoreDisplay.Get(ruleset);
if (scoreDisplay == null) return;

if (!PerformanceCounter.TryGetTarget(out var sprite))
if (!PerformanceCounter.TryGetTarget(out var sprite) || sprite == null)
return;

pText.SetText.Invoke(sprite, [$"{pp:00.0}pp"]);
Expand All @@ -41,26 +39,4 @@ public static void UpdatePerformanceCounter(double pp)
Console.WriteLine($"Failed to set performance counter sprite text: {e}");
}
}
}

// [HarmonyPatch]
// public class fhjks
// {
// static fhjks()
// {
// Console.WriteLine("sinit");
// }
//
// [HarmonyTargetMethod]
// private static MethodBase fjhsdf() => pSpriteText.Constructor.Reference;
//
// [HarmonyPrefix]
// private static void before(
// [HarmonyArgument(0)] string text,
// [HarmonyArgument(1)] string abc,
// [HarmonyArgument(2)] float abcd
// )
// {
// Console.WriteLine($"{text} {abc} {abcd}");
// }
// }
}
15 changes: 15 additions & 0 deletions Osu.Stubs/Opcode/LazyField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,19 @@ public FieldInfo Reference
/// <returns>The current field value casted to the type defined by this LazyField.</returns>
public T Get(object? instance = null) =>
(T)Reference.GetValue(instance);

/// <summary>
/// Set a instance field to a specific value.
/// </summary>
/// <param name="instance">An instance of the field's enclosing class.</param>
/// <param name="value">The new value.</param>
public void Set(object instance, T value) =>
Reference.SetValue(instance, value);

/// <summary>
/// Set a static field to a specific value.
/// </summary>
/// <param name="value">The new value.</param>
public void Set(T value) =>
Reference.SetValue(null, value);
}
2 changes: 1 addition & 1 deletion Osu.Stubs/ScoreDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class ScoreDisplay
/// b20240123: <c>#=zRjDThRI=</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyMethod Hide = new(
public static readonly LazyMethod Hide = new( // TODO: support hiding performance counter
"ScoreDisplay#Hide()",
new[]
{
Expand Down
51 changes: 51 additions & 0 deletions Osu.Stubs/SkinManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Linq;
using HarmonyLib;
using JetBrains.Annotations;
using Osu.Stubs.Opcode;
using static System.Reflection.Emit.OpCodes;

namespace Osu.Stubs;

/// <summary>
/// Original: <c>osu.Graphics.Skinning.SkinManager</c>
/// b20240123: <c>#=zdwZLyAQXwqtPhTfOQ$e2PRLm39DcCX13EA==</c>
/// </summary>
[UsedImplicitly]
public static class SkinManager
{
/// <summary>
/// Original: <c>get_UseNewLayout()</c>
/// b20240123: <c>#=zOwgqVurLFLwR</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyMethod<bool> GetUseNewLayout = new(
"SkinManager#get_UseNewLayout()",
new[]
{
Ldsfld,
Brfalse_S,
Call,
Brtrue_S,
Ldsfld,
Brfalse_S,
Ldsfld,
Ldfld,
}
);

/// <summary>
/// Original: <c>Current</c>
/// b20240123: <c>#=zUzFTHbU=</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyField<object> Current = new(
"SkinManager#Current",
// There is two fields with type SkinOsu; Current and CurrentUserSkin in that order
() => RuntimeType.GetDeclaredFields()
.First(f => f.FieldType == SkinOsu.RuntimeType)
);

[UsedImplicitly]
public static Type RuntimeType = GetUseNewLayout.Reference.DeclaringType!;
}
40 changes: 40 additions & 0 deletions Osu.Stubs/SkinOsu.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using HarmonyLib;
using JetBrains.Annotations;
using Osu.Stubs.Opcode;

namespace Osu.Stubs;

/// <summary>
/// Original: <c>osu.Graphics.Skinning.OsuSkin</c>
/// b20240123: <c>osu.Graphics.Skinning.OsuSkin</c>
/// Most names are present because of this class is [Serializable].
/// </summary>
[UsedImplicitly]
public static class SkinOsu
{
/// <summary>
/// Original: <c>FontScoreOverlap</c>
/// b20240123: <c>FontScoreOverlap</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyField<int> FontScoreOverlap = new(
"OsuSkin#FontScoreOverlap",
() => RuntimeType.GetDeclaredFields()
.Find(f => f.Name == "FontScoreOverlap")
);

/// <summary>
/// Original: <c>FontScore</c>
/// b20240123: <c>FontScore</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyField<string> FontScore = new(
"OsuSkin#FontScore",
() => RuntimeType.GetDeclaredFields()
.Find(f => f.Name == "FontScore")
);

[UsedImplicitly]
public static Type RuntimeType => OsuAssembly.GetType("osu.Graphics.Skinning.SkinOsu");
}
100 changes: 100 additions & 0 deletions Osu.Stubs/pDrawable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using HarmonyLib;
using JetBrains.Annotations;
using Osu.Stubs.Opcode;
using static System.Reflection.Emit.OpCodes;

namespace Osu.Stubs;

/// <summary>
/// Original: <c>osu.Graphics.pDrawable</c>
/// b20240123: <c>#=zB63SnFDTnRqYMKLlscCRpu_ww$IG</c>
/// </summary>
[UsedImplicitly]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static class pDrawable
{
/// <summary>
/// Original: <c>Click(bool confirmed)</c>
/// b20240123: <c>#=zcJ6mazw=</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyMethod<bool> Click = new(
"pDrawable#Click(...)",
new[]
{
Ret,
Ldarg_0,
Ldfld,
Ldnull,
Cgt_Un,
Dup,
Brfalse_S,
Ldarg_0,
Ldfld,
}
);

/// <summary>
/// Original: <c>ScaleTo(float final, int duration, EasingTypes easing)</c>
/// b20240123: <c>#=zVyF2njk=</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyMethod<object> ScaleTo = new(
"pDrawable#ScaleTo(...)",
new[]
{
Ldc_I4_4, // TransformationType.Scale
Ldarg_0,
Ldfld, // this.Scale
Conv_R4,
Ldarg_1,
Ldarg_0,
Ldfld,
Call,
Ldsfld,
Conv_I4,
Sub,
}
);

/// <summary>
/// Original: <c>Position</c>
/// b20240123: <c>#=ztOn8vDI=</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyField<object> Position = new(
"pDrawable#Position",
// There is 3 fields with a type of <c>Vector2</c> on this class. The middle one is <c>Position</c>.
() => RuntimeType.GetDeclaredFields().AsEnumerable()
.Reverse()
.Where(field => field.FieldType == Vector2.RuntimeType)
.Skip(1)
.First()
);

/// <summary>
/// Original: <c>Scale</c>
/// b20240123: <c>#=zmbpQ79A=</c>
/// </summary>
[UsedImplicitly]
public static readonly LazyField<float> Scale = new(
"pDrawable#Scale",
() =>
{
// The last "ldsfld float" in the ScaleTo method is a reference to this.Scale
var instruction = MethodReader.GetInstructions(ScaleTo.Reference)
.Reverse()
.Where(inst => inst.Opcode == Ldfld)
.First(inst => ((FieldInfo)inst.Operand).FieldType == typeof(float));

return (FieldInfo)instruction.Operand;
}
);

[UsedImplicitly]
public static Type RuntimeType => ScaleTo.Reference.DeclaringType!;
}
Loading

0 comments on commit b792aa4

Please sign in to comment.