diff --git a/Celeste.Mod.mm/Patches/Actor.cs b/Celeste.Mod.mm/Patches/Actor.cs index f48c19fd6..b1f00a995 100644 --- a/Celeste.Mod.mm/Patches/Actor.cs +++ b/Celeste.Mod.mm/Patches/Actor.cs @@ -1,13 +1,10 @@ #pragma warning disable CS0626 // Method, operator, or accessor is marked external and has no attributes on it using Microsoft.Xna.Framework; -using MonoMod; namespace Celeste { class patch_Actor : Actor { - private Vector2 movementCounter = default; - public patch_Actor(Vector2 position) : base(position) { // no-op. MonoMod ignores this - we only need this to make the compiler shut up. @@ -18,17 +15,5 @@ protected bool TrySquishWiggle(CollisionData data) { return TrySquishWiggle(data, 3, 3); } - // Patch MoveToX/Y to replicate XNA's behaviour on FNA - - [MonoModReplace] - public new void MoveToX(float toX, Collision onCollide = null) { - MoveH((float) ((double) toX - Position.X - movementCounter.X), onCollide); - } - - [MonoModReplace] - public new void MoveToY(float toY, Collision onCollide = null) { - MoveV((float) ((double) toY - Position.Y - movementCounter.Y), onCollide); - } - } } diff --git a/Celeste.Mod.mm/Patches/Bumper.cs b/Celeste.Mod.mm/Patches/Bumper.cs deleted file mode 100644 index 986d4418b..000000000 --- a/Celeste.Mod.mm/Patches/Bumper.cs +++ /dev/null @@ -1,24 +0,0 @@ -#pragma warning disable CS0626 // Method, operator, or accessor is marked external and has no attributes on it -#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value - -using Microsoft.Xna.Framework; -using Monocle; -using MonoMod; - -namespace Celeste { - class patch_Bumper : Bumper { - - private Vector2 anchor; - private SineWave sine; - - public patch_Bumper(EntityData data, Vector2 offset) : base(data, offset) { - //no-op, ignored by MonoMod - } - - [MonoModReplace] - private void UpdatePosition() { - Position = new Vector2((float) ((double) anchor.X + sine.Value * 3.0), (float) ((double) anchor.Y + sine.ValueOverTwo * 2.0)); - } - - } -} \ No newline at end of file diff --git a/Celeste.Mod.mm/Patches/DreamBlock.cs b/Celeste.Mod.mm/Patches/DreamBlock.cs index 298222fd3..0fd5232e9 100644 --- a/Celeste.Mod.mm/Patches/DreamBlock.cs +++ b/Celeste.Mod.mm/Patches/DreamBlock.cs @@ -1,21 +1,11 @@ using Microsoft.Xna.Framework; -using Mono.Cecil; -using Mono.Cecil.Cil; using Monocle; using MonoMod; -using MonoMod.Cil; using System; using System.Collections; -using System.Runtime.CompilerServices; -using System.Linq; namespace Celeste { class patch_DreamBlock : DreamBlock { - - internal Vector2 movementCounter { - [MonoModLinkTo("Celeste.Platform", "get__movementCounter")] get; - } - private bool playerHasDreamDash; private LightOcclude occlude; private float whiteHeight; @@ -38,10 +28,6 @@ public void ctor(Vector2 position, float width, float height, Vector2? node, boo ctor(position, width, height, node, fastMoving, oneUse, false); } - [MonoModIgnore] - [PatchDreamBlockSetup] - public new extern void Setup(); - public void DeactivateNoRoutine() { if (playerHasDreamDash) { playerHasDreamDash = false; @@ -199,71 +185,5 @@ private Vector2 PutInside(Vector2 pos) { } return pos; } - - // Patch XNA/FNA jank in Tween.OnUpdate lambda - [MonoModPatch("<>c__DisplayClass22_0")] - class patch_AddedLambdas { - - [MonoModPatch("<>4__this")] - private patch_DreamBlock _this = default; - private Vector2 start = default, end = default; - - [MonoModReplace] - [MonoModPatch("b__0")] - public void TweenUpdateLambda(Tween t) { - // Patch this to always behave like XNA - // This is absolutely hecking ridiculous and a perfect example of why we want to switch to .NET Core - // The Y member gets downcast but not the X one because of JIT jank - double lerpX = start.X + ((double) end.X - start.X) * t.Eased, lerpY = start.Y + ((double) end.Y - start.Y) * t.Eased; - float moveHDelta = (float) (lerpX - _this.Position.X - _this.movementCounter.X), moveVDelta = (float) ((double) JITBarrier((float) lerpY) - _this.Position.Y - _this.movementCounter.Y); - if (_this.Collidable) { - _this.MoveH(moveHDelta); - _this.MoveV(moveVDelta); - } else { - _this.MoveHNaive(moveHDelta); - _this.MoveVNaive(moveVDelta); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static float JITBarrier(float v) => v; - - } - } } - -namespace MonoMod { - /// - /// Patches to not rely on - /// non-IEEE 754 compliant .NET Framework jank anymore, by patching the - /// dream block particle count calculation to be done using doubles (the x86 - /// .NET Framework JIT uses 80 bit x87 registers for this calculation, - /// however 64 bit doubles seem to have enough precision to end up at the - /// same results). This fixes issue #556. - /// - [MonoModCustomMethodAttribute(nameof(MonoModRules.PatchDreamBlockSetup))] - class PatchDreamBlockSetupAttribute : Attribute {} - - static partial class MonoModRules { - - public static void PatchDreamBlockSetup(ILContext context, CustomAttribute attrib) { - // Patch instructions before the 'conv.i4' cast to use doubles instead of floats - for (int i = 0; i < context.Instrs.Count; i++) { - Instruction instr = context.Instrs[i]; - - if (instr.MatchConvI4()) - break; - - // call(virt) - if (instr.MatchCallOrCallvirt(out MethodReference method) && method.ReturnType.MetadataType == MetadataType.Single) - context.Instrs.Insert(++i, Instruction.Create(OpCodes.Conv_R8)); // cast return value to double - - // ldc.r4 - if (instr.MatchLdcR4(out float val)) - context.Instrs[i] = Instruction.Create(OpCodes.Ldc_R8, (double) val); - } - } - - } -} \ No newline at end of file diff --git a/Celeste.Mod.mm/Patches/FNA/MathHelper.cs b/Celeste.Mod.mm/Patches/FNA/MathHelper.cs deleted file mode 100644 index 1dbb618ec..000000000 --- a/Celeste.Mod.mm/Patches/FNA/MathHelper.cs +++ /dev/null @@ -1,38 +0,0 @@ -using MonoMod; -using System; - -namespace Microsoft.Xna.Framework { - [GameDependencyPatch("FNA")] - struct patch_MathHelper { - - // Patch x87 floating point jank (see patch_VectorXYZ for more details) - // Inlining might potentially affect SmoothStep - patch if that ever becomes an issue - - public static Color NewColor(Color color, int alpha) => new Color(color.R, color.G, color.B, alpha); - public static Color NewColor(Color color, float alpha) => new Color(color.R, color.G, color.B, (byte) alpha * 255); - - [MonoModReplace] - public static float Barycentric(float value1, float value2, float value3, float amount1, float amount2) { - return (float) ((double) value1 + ((double) value2 - value1) * amount1 + ((double) value3 - value1) * amount2); - } - - [MonoModReplace] - public static float Lerp(float value1, float value2, float amount) { - return (float) ((double) value1 + ((double) value2 - value1) * amount); - } - - [MonoModReplace] - public static float WrapAngle(float angle) { - if (angle > -Math.PI && angle <= Math.PI) - return angle; - - angle = (float) (angle % (Math.PI * 2.0)); - if (angle <= -Math.PI) - return (float) (angle + Math.PI * 2.0); - if (angle > Math.PI) - return (float) (angle - Math.PI * 2.0); - return angle; - } - - } -} diff --git a/Celeste.Mod.mm/Patches/FNA/Vector.cs b/Celeste.Mod.mm/Patches/FNA/Vector.cs deleted file mode 100644 index 56e1cf717..000000000 --- a/Celeste.Mod.mm/Patches/FNA/Vector.cs +++ /dev/null @@ -1,225 +0,0 @@ -using MonoMod; -using System; - -namespace Microsoft.Xna.Framework { - // Patch some Vector2/3/4 methods because they execute with more precision than they should on .NET Framework - // To preserve compatibilty, we need to ensure that these methods execute with higher precision as well - - // DON'T. TOUCH. THIS. - // For the sake of your own sanity, only mess with the below code when forced to at gunpoint - // If you still do, run the full 100% and any% TASes afterwards - // Don't be surprised if stuff falls apart, I've warned you - // Note that the only way to reliably determine the correct behaviour here is to inspect the x86 assembly code emitted by the .NET Framework JIT - // (everything also depends on if the assembly was compiled in Debug/Release mode - there's your XNA/FNA desyncs) - - [GameDependencyPatch("FNA")] - struct patch_Vector2 { - - public float X, Y; - - [MonoModReplace] - public float Length() => (float) Math.Sqrt((double) X * (double) X + (double) Y * (double) Y); - - [MonoModReplace] - public float LengthSquared() => (float) ((double) X * (double) X + (double) Y * (double) Y); - - [MonoModReplace] - public void Normalize() { - double invLen = 1.0 / (float) Math.Sqrt((double) X * (double) X + (double) Y * (double) Y); - X = (float) (X * invLen); - Y = (float) (Y * invLen); - } - - [MonoModReplace] - public static Vector2 Normalize(Vector2 v) { - v.Normalize(); - return v; - } - - [MonoModReplace] - public static void Normalize(ref Vector2 v, out Vector2 o) { - o = v; - o.Normalize(); - } - - [MonoModReplace] - public static float Distance(Vector2 a, Vector2 b) { - double xD = (double) a.X - (double) b.X, yD = (double) a.Y - (double) b.Y; - return (float) Math.Sqrt(xD*xD + yD*yD); - } - - [MonoModReplace] - public static void Distance(ref Vector2 a, ref Vector2 b, out float r) => r = Distance(a, b); - - [MonoModReplace] - public static float DistanceSquared(Vector2 a, Vector2 b) { - double xD = (double) a.X - (double) b.X, yD = (double) a.Y - (double) b.Y; - return (float) (xD*xD + yD*yD); - } - - [MonoModReplace] - public static void DistanceSquared(ref Vector2 a, ref Vector2 b, out float r) => r = DistanceSquared(a, b); - - [MonoModReplace] - public static float Dot(Vector2 a, Vector2 b) => (float) ((double) a.X * b.X + (double) a.Y * b.Y); - - [MonoModReplace] - public static void Dot(ref Vector2 a, ref Vector2 b, out float r) => r = (float) ((double) a.X * b.X + (double) a.Y * b.Y); - - [MonoModReplace] - public static Vector2 Divide(Vector2 v, float s) => new Vector2(v.X / s, v.Y / s); - - [MonoModReplace] - public static void Divide(ref Vector2 v, float s, out Vector2 r) { - r.X = v.X / s; - r.Y = v.Y / s; - } - - [MonoModReplace] - public static Vector2 operator /(patch_Vector2 v, float s) => new Vector2(v.X / s, v.Y / s); - - } - - [GameDependencyPatch("FNA")] - struct patch_Vector3 { - - public float X, Y, Z; - - [MonoModReplace] - public float Length() => (float) Math.Sqrt((double) X * (double) X + (double) Y * (double) Y + (double) Z * (double) Z); - - [MonoModReplace] - public float LengthSquared() => (float) ((double) X * (double) X + (double) Y * (double) Y + (double) Z * (double) Z); - - [MonoModReplace] - public void Normalize() { - double invLen = 1.0 / (float) Math.Sqrt((double) X * (double) X + (double) Y * (double) Y + (double) Z * (double) Z); - X = (float) (X * invLen); - Y = (float) (Y * invLen); - Z = (float) (Z * invLen); - } - - [MonoModReplace] - public static Vector3 Normalize(Vector3 v) { - v.Normalize(); - return v; - } - - [MonoModReplace] - public static void Normalize(ref Vector3 v, out Vector3 o) { - o = v; - o.Normalize(); - } - - [MonoModReplace] - public static float Distance(Vector3 a, Vector3 b) { - double xD = (double) a.X - (double) b.X, yD = (double) a.Y - (double) b.Y, zD = (double) a.Z - (double) b.Z; - return (float) Math.Sqrt(xD*xD + yD*yD + zD*zD); - } - - [MonoModReplace] - public static void Distance(ref Vector3 a, ref Vector3 b, out float r) => r = Distance(a, b); - - [MonoModReplace] - public static float DistanceSquared(Vector3 a, Vector3 b) { - double xD = (double) a.X - (double) b.X, yD = (double) a.Y - (double) b.Y, zD = (double) a.Z - (double) b.Z; - return (float) (xD*xD + yD*yD + zD*zD); - } - - [MonoModReplace] - public static void DistanceSquared(ref Vector3 a, ref Vector3 b, out float r) => r = DistanceSquared(a, b); - - [MonoModReplace] - public static float Dot(Vector3 a, Vector3 b) => (float) ((double) a.X * b.X + (double) a.Y * b.Y + (double) a.Z * b.Z); - - [MonoModReplace] - public static void Dot(ref Vector3 a, ref Vector3 b, out float r) => r = (float) ((double) a.X * b.X + (double) a.Y * b.Y + (double) a.Z * b.Z); - - [MonoModReplace] - public static Vector3 Divide(Vector3 v, float s) => new Vector3(v.X / s, v.Y / s, v.Z / s); - - [MonoModReplace] - public static void Divide(ref Vector3 v, float s, out Vector3 r) { - r.X = v.X / s; - r.Y = v.Y / s; - r.Z = v.Z / s; - } - - [MonoModReplace] - public static Vector3 operator /(patch_Vector3 v, float s) => new Vector3(v.X / s, v.Y / s, v.Z / s); - - } - - - [GameDependencyPatch("FNA")] - struct patch_Vector4 { - - public float X, Y, Z, W; - - [MonoModReplace] - public float Length() => (float) Math.Sqrt((double) X * (double) X + (double) Y * (double) Y + (double) Z * (double) Z + (double) W * (double) W); - - [MonoModReplace] - public float LengthSquared() => (float) ((double) X * (double) X + (double) Y * (double) Y + (double) Z * (double) Z + (double) W * (double) W); - - [MonoModReplace] - public void Normalize() { - double invLen = 1.0 / (float) Math.Sqrt((double) X * (double) X + (double) Y * (double) Y + (double) Z * (double) Z + (double) W * (double) W); - X = (float) (X * invLen); - Y = (float) (Y * invLen); - Z = (float) (Z * invLen); - W = (float) (W * invLen); - } - - [MonoModReplace] - public static Vector4 Normalize(Vector4 v) { - v.Normalize(); - return v; - } - - [MonoModReplace] - public static void Normalize(ref Vector4 v, out Vector4 o) { - o = v; - o.Normalize(); - } - - [MonoModReplace] - public static float Distance(Vector4 a, Vector4 b) { - double xD = (double) a.X - (double) b.X, yD = (double) a.Y - (double) b.Y, zD = (double) a.Z - (double) b.Z, wD = (double) a.W - (double) b.W; - return (float) Math.Sqrt(xD*xD + yD*yD + zD*zD + wD*wD); - } - - [MonoModReplace] - public static void Distance(ref Vector4 a, ref Vector4 b, out float r) => r = Distance(a, b); - - [MonoModReplace] - public static float DistanceSquared(Vector4 a, Vector4 b) { - double xD = (double) a.X - (double) b.X, yD = (double) a.Y - (double) b.Y, zD = (double) a.Z - (double) b.Z, wD = (double) a.W - (double) b.W; - return (float) (xD*xD + yD*yD + zD*zD + wD*wD); - } - - [MonoModReplace] - public static void DistanceSquared(ref Vector4 a, ref Vector4 b, out float r) => r = DistanceSquared(a, b); - - [MonoModReplace] - public static float Dot(Vector4 a, Vector4 b) => (float) ((double) a.X * b.X + (double) a.Y * b.Y + (double) a.Z * b.Z + (double) a.W * b.W); - - [MonoModReplace] - public static void Dot(ref Vector4 a, ref Vector4 b, out float r) => r = (float) ((double) a.X * b.X + (double) a.Y * b.Y + (double) a.Z * b.Z + (double) a.W * b.W); - - [MonoModReplace] - public static Vector4 Divide(Vector4 v, float s) => new Vector4(v.X / s, v.Y / s, v.Z / s, v.W / s); - - [MonoModReplace] - public static void Divide(ref Vector4 v, float s, out Vector4 r) { - r.X = v.X / s; - r.Y = v.Y / s; - r.Z = v.Z / s; - r.W = v.W / s; - } - - [MonoModReplace] - public static Vector4 operator /(patch_Vector4 v, float s) => new Vector4(v.X / s, v.Y / s, v.Z / s, v.W / s); - - } -} \ No newline at end of file diff --git a/Celeste.Mod.mm/Patches/FinalBossMovingBlock.cs b/Celeste.Mod.mm/Patches/FinalBossMovingBlock.cs deleted file mode 100644 index 5dd46ed7f..000000000 --- a/Celeste.Mod.mm/Patches/FinalBossMovingBlock.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Microsoft.Xna.Framework; -using Monocle; -using MonoMod; -using System.Runtime.CompilerServices; - -namespace Celeste { - class patch_FinalBossMovingBlock : FinalBossMovingBlock { - - internal Vector2 movementCounter { - [MonoModLinkTo("Celeste.Platform", "get__movementCounter")] get; - } - - public patch_FinalBossMovingBlock(EntityData data, Vector2 offset) - : base(data, offset) { - // no-op. MonoMod ignores this - we only need this to make the compiler shut up. - } - - [MonoModPatch("<>c__DisplayClass14_0")] - class patch_MoveSequenceLambdas { - - [MonoModPatch("<>4__this")] - private patch_FinalBossMovingBlock _this = default; - private Vector2 from = default, to = default; - - [MonoModReplace] - [MonoModPatch("b__0")] - public void TweenUpdateLambda(Tween t) { - // Patch this to always behave like XNA - // This is absolutely hecking ridiculous and a perfect example of why we want to switch to .NET Core - // The Y member gets downcast but not the X one because of JIT jank - double lerpX = from.X + ((double) to.X - from.X) * t.Eased, lerpY = from.Y + ((double) to.Y - from.Y) * t.Eased; - _this.MoveH((float) (lerpX - _this.Position.X - _this.movementCounter.X)); - _this.MoveV((float) ((double) JITBarrier((float) lerpY) - _this.Position.Y - _this.movementCounter.Y)); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static float JITBarrier(float v) => v; - - } - - } -} \ No newline at end of file diff --git a/Celeste.Mod.mm/Patches/FloatySpaceBlock.cs b/Celeste.Mod.mm/Patches/FloatySpaceBlock.cs deleted file mode 100644 index ab30fdc5d..000000000 --- a/Celeste.Mod.mm/Patches/FloatySpaceBlock.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.Xna.Framework; -using Monocle; -using MonoMod; -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace Celeste { - class patch_FloatySpaceBlock : FloatySpaceBlock { - - private float sineWave = default, dashEase = default, yLerp = default; - private Vector2 dashDirection = default; - - public patch_FloatySpaceBlock(EntityData data, Vector2 offset) - : base(data, offset) { - // no-op. MonoMod ignores this - we only need this to make the compiler shut up. - } - - //Might not be 100% accurate (I didn't check .NET Framework JIT output assembly for this), but good enough for now to make the TAS resync - [MonoModReplace] - private void MoveToTarget() { - float sineVal = (float) (JITBarrier(4.0f) * (double) Math.Sin(sineWave)); //We can't use 4.0 directly because mods might look for this constant - Vector2 dashVec = Calc.YoYo(Ease.QuadIn(dashEase)) * dashDirection * 8f; //No doubles here cause vector scalar multiplication acts like a JIT barrier - for (int i = 0; i < 2; i++) { - foreach (KeyValuePair move in Moves) { - Platform platform = move.Key; - bool hasRider = false; - - JumpThru jumpThru = platform as JumpThru; - Solid solid = platform as Solid; - if ((jumpThru != null && jumpThru.HasRider()) || (solid != null && solid.HasRider())) - hasRider = true; - - if ((hasRider || i != 0) && (!hasRider || i != 1)) { - Vector2 moveVal = move.Value; - double yVal = (double) moveVal.Y + JITBarrier(12.0f) * (double) Ease.SineInOut(yLerp) + sineVal; //We can't use 12.0 directly because might mods look for this constant - platform.MoveToY((float) (yVal + dashVec.Y)); - platform.MoveToX(moveVal.X + dashVec.X); - } - } - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static float JITBarrier(float v) => v; - - } -} \ No newline at end of file diff --git a/Celeste.Mod.mm/Patches/LavaRect.cs b/Celeste.Mod.mm/Patches/LavaRect.cs index b88af1087..f15fc0d3a 100644 --- a/Celeste.Mod.mm/Patches/LavaRect.cs +++ b/Celeste.Mod.mm/Patches/LavaRect.cs @@ -1,11 +1,4 @@ using Celeste.Mod.Helpers; -using Mono.Cecil; -using Mono.Cecil.Cil; -using MonoMod; -using MonoMod.Cil; -using MonoMod.InlineRT; -using MonoMod.Utils; -using System; namespace Celeste { class patch_LavaRect : LavaRect { @@ -14,127 +7,9 @@ public patch_LavaRect(float width, float height, int step) : base(width, height, // no-op. MonoMod ignores this - we only need this to make the compiler shut up. } - [MonoModIgnore] - [PatchLavaRectResize] - public new extern void Resize(float width, float height, int step); - - [MonoModIgnore] - [PatchLavaRectRender] - public override extern void Render(); - - [MonoModIgnore] - [PatchLavaRectUpdate] - public override extern void Update(); - private bool IsVisible() { var renderPos = Entity.Position + Position; return CullHelper.IsRectangleVisible(renderPos.X, renderPos.Y, Width, Height, lenience: 8f); } } -} - -namespace MonoMod { - /// - /// Patch LavaRect.Resize to perform calculations using doubles instead of floats, fixing float jank on .NET Core Everest. - /// - [MonoModCustomMethodAttribute(nameof(MonoModRules.PatchLavaRectResize))] - class PatchLavaRectResizeAttribute : Attribute { } - - /// - /// Patch LavaRect.Render to fix the half pixel offset issue on FNA. This is planned to be patched in Celeste 1.4.1.0! - /// Also implements camera culling. - /// - [MonoModCustomMethodAttribute(nameof(MonoModRules.PatchLavaRectRender))] - class PatchLavaRectRenderAttribute : Attribute { } - - /// - /// Patch LavaRect.Update to implement camera culling. - /// - [MonoModCustomMethodAttribute(nameof(MonoModRules.PatchLavaRectUpdate))] - class PatchLavaRectUpdateAttribute : Attribute { } - - static partial class MonoModRules { - - public static void PatchLavaRectResize(ILContext context, CustomAttribute attrib) { - for (ILCursor cursor = new ILCursor(context); cursor.Next != null; cursor.Index++) { - Instruction instr = cursor.Next; - if (instr.MatchLdcR4(out float v)) { - // ldc.r4 -> ...; conv.r8 - cursor.Index++; - cursor.Emit(OpCodes.Conv_R8); - cursor.Index--; - } else if (instr.MatchConvR4()) { - // conv.r4 -> conv.r8 - cursor.Remove(); - cursor.Emit(OpCodes.Conv_R8); - } else if (instr.MatchLdarg(out int idx)) { - // ldarg -> ...; conv.r8 - if (idx == 0 || context.Method.Parameters[idx-1].ParameterType.MetadataType != MetadataType.Single) - continue; - - cursor.Index++; - cursor.Emit(OpCodes.Conv_R8); - cursor.Index--; - } else if (instr.MatchCall(out MethodReference methodRef)) { - // Adjust the function signature to use doubles instead of floats - MethodReference adjRef = new MethodReference(methodRef.Name, methodRef.ReturnType, methodRef.DeclaringType); - - if (adjRef.ReturnType.MetadataType == MetadataType.Single) - adjRef.ReturnType = context.Module.TypeSystem.Double; - - foreach (ParameterDefinition param in methodRef.Parameters) { - if (param.ParameterType.MetadataType != MetadataType.Single) - adjRef.Parameters.Add(param); - else - adjRef.Parameters.Add(new ParameterDefinition(context.Module.TypeSystem.Double)); - } - - instr.Operand = adjRef; - } else if (instr.MatchBr(out _)) - // Abort once we hit the loop - break; - } - } - - public static void PatchLavaRectRender(ILContext context, CustomAttribute attrib) { - ILCursor cursor = new ILCursor(context); - - // Insert this code at the start of the method: - // if (!IsVisible()) - // return; - cursor.Emit(OpCodes.Ldarg_0); - cursor.Emit(OpCodes.Call, context.Method.DeclaringType.FindMethod("System.Boolean IsVisible()")!); - ILLabel label = cursor.DefineLabel(); - cursor.Emit(OpCodes.Brtrue, label); - cursor.Emit(OpCodes.Ret); - cursor.MarkLabel(label); - - // The half pixel offset issue was fixed in 1.4.1.0 - if (CurrentGameVersion >= new Version(1, 4, 1, 0)) return; - - MethodReference m_Vector2_op_Addition = null; - cursor.GotoNext(MoveType.After, instr => instr.MatchLdfld("Celeste.LavaRect", "Position"), instr => instr.MatchCall(out m_Vector2_op_Addition)); - - MethodReference m_Vector2_ctor = MonoModRule.Modder.Module.ImportReference(m_Vector2_op_Addition.DeclaringType.Resolve().FindMethod("System.Void Microsoft.Xna.Framework.Vector2::.ctor(System.Single,System.Single)")!); - cursor.EmitLdcR4(0.5f); - cursor.EmitDup(); - cursor.EmitNewobj(m_Vector2_ctor); - cursor.EmitCall(m_Vector2_op_Addition); - } - - public static void PatchLavaRectUpdate(ILContext context, CustomAttribute attrib) { - ILCursor cursor = new ILCursor(context); - - // Insert this code at the start of the method: - // if (!IsVisible()) - // return; - - cursor.Emit(OpCodes.Ldarg_0); - cursor.Emit(OpCodes.Call, context.Method.DeclaringType.FindMethod("System.Boolean IsVisible()")!); - ILLabel label = cursor.DefineLabel(); - cursor.Emit(OpCodes.Brtrue, label); - cursor.Emit(OpCodes.Ret); - cursor.MarkLabel(label); - } - } } \ No newline at end of file diff --git a/Celeste.Mod.mm/Patches/Monocle/Calc.cs b/Celeste.Mod.mm/Patches/Monocle/Calc.cs index bf124c457..f54ca0de4 100644 --- a/Celeste.Mod.mm/Patches/Monocle/Calc.cs +++ b/Celeste.Mod.mm/Patches/Monocle/Calc.cs @@ -47,34 +47,6 @@ public static bool XMLExists(string filename) { return true; } - [MonoModReplace] - public static float Percent(float num, float zeroAt, float oneAt) { - // return MathHelper.Clamp((num - zeroAt) / oneAt, 0f, 1f); - return MathHelper.Clamp((num - zeroAt) / (oneAt - zeroAt), 0f, 1f); - } - - [MonoModReplace] - public static Vector2 Approach(Vector2 val, Vector2 target, float maxMove) { - if (maxMove == 0f || val == target) - return val; - - Vector2 delta = target - val; - if (delta.Length() < maxMove) - return target; - - delta.Normalize(); - return new Vector2((float) (val.X + (double) delta.X * maxMove), (float) (val.Y + (double) delta.Y * maxMove)); // Patch in XNA float jank - } - - [MonoModReplace] - public static Vector3 Approach(this Vector3 v, Vector3 target, float amount) { - if (amount > (target - v).Length()) - return target; - - Vector3 delta = (target - v).SafeNormalize(); - return new Vector3((float) (v.X + (double) delta.X * amount), (float) (v.Y + (double) delta.Y * amount), (float) (v.Z + (double) delta.Z * amount)); // Patch in XNA float jank - } - /// /// Convert a hex color, possibly including an alpha value, into an XNA Color. /// @@ -116,6 +88,5 @@ public static Color HexToColorWithAlpha(string hex) { return Color.White; } } - } } diff --git a/Celeste.Mod.mm/Patches/Monocle/Ease.cs b/Celeste.Mod.mm/Patches/Monocle/Ease.cs deleted file mode 100755 index 24647c0c3..000000000 --- a/Celeste.Mod.mm/Patches/Monocle/Ease.cs +++ /dev/null @@ -1,106 +0,0 @@ -using MonoMod; -using System; - -namespace Monocle { - // A lot of the easer implementations are heavily affected by .NET Framwork higher-precision jank - // Patch those to work with doubles to at least remedy the situation - [MonoModPatch("Monocle.Ease/<>c")] - class EaserPatch { - - // We can't MonoModReplace the easers, because of the dot in the name ._. - - private const string EaserClassFName = "Monocle.Ease/<>c"; - private const double B1 = 0.363636374f, B2 = 0.727272749f, B3 = 0.545454562f, B4 = 0.909090936f, B5 = 0.8181818f, B6 = 0.954545438f; - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_1(System.Single)")] - public float SineIn(float t) => (float) (-(double) (float) Math.Cos((float) (Math.PI/2) * (double) t) + 1.0); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_2(System.Single)")] - public float SineOut(float t) => (float) Math.Sin((float) (Math.PI/2) * (double) t); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_3(System.Single)")] - public float SineInOut(float t) => (float) (-(double) (float) Math.Cos(Math.PI * (double) t) / 2.0 + 0.5); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_4(System.Single)")] - public float QuadIn(float t) => (float) ((double) t * (double) t); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_5(System.Single)")] - public float CubeIn(float t) => (float) ((double) t * (double) t * (double) t); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_6(System.Single)")] - public float QuintIn(float t) => (float) ((double) t * (double) t * (double) t * (double) t * (double) t); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_7(System.Single)")] - public float ExpoIn(float t) => (float) Math.Pow(2.0, 10.0 * ((double) t - 1.0)); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_8(System.Single)")] - public float BackIn(float t) => (float) ((double) t * (double) t * (2.70158f * (double) t - 1.70158f)); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_9(System.Single)")] - public float BigBackIn(float t) => (float) ((double) t * (double) t * (4f * (double) t - 3f)); - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_10(System.Single)")] - public float ElasticIn(float t) { - double t2 = (float) ((double) t * (double) t), t3 = (float) (t2 * (double) t); - return (float) (33.0*t2*t3 + -59.0*t2*t2 + 32.0*t3 + -5.0*t2); - } - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_11(System.Single)")] - public float ElasticOut(float t) { - double t2 = (float) ((double) t * (double) t), t3 = (float) (t2 * (double) t); - return (float) (33.0*t2*t3 + -106.0*t2*t2 + 126.0*t3 + -67.0*t2 + 15.0*t); - } - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_12(System.Single)")] - public float BounceIn(float t) { - double td = 1.0 - t; - if (td < B1) - return (float) (1.0 - 1.0/(B1*B1) * td * td); - else if (td < B2) - return (float) (1.0 - (1.0/(B1*B1) * (td - B3) * (td - B3) + (1.0 - 1.0 / 4))); - else if (td < B4) - return (float) (1.0 - (1.0/(B1*B1) * (td - B5) * (td - B5) + (1.0 - 1.0 / (4*4)))); - else - return (float) (1.0 - (1.0/(B1*B1) * (td - B6) * (td - B6) + (1.0 - 1.0 / (4*4*4)))); - } - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_13(System.Single)")] - public float BounceOut(float t) { - double td = t; - if (td < B1) - return (float) (1.0/(B1*B1) * td * td); - else if (td < B2) - return (float) (1.0/(B1*B1) * (td - B3) * (td - B3) + (1.0 - 1.0 / 4)); - else if (td < B4) - return (float) (1.0/(B1*B1) * (td - B5) * (td - B5) + (1.0 - 1.0 / (4*4))); - else - return (float) (1.0/(B1*B1) * (td - B6) * (td - B6) + (1.0 - 1.0 / (4*4*4))); - } - - [MonoModLinkFrom($"System.Single {EaserClassFName}::<.cctor>b__38_14(System.Single)")] - public float BounceInOut(float t) { - if (t < 0.5f) { - double td = 1.0 - t * 2.0; - if (td < B1) - return (float) ((1.0 - 1.0/(B1*B1) * td * td) / 2.0); - else if (td < B2) - return (float) ((1.0 - (1.0/(B1*B1) * (td - B3) * (td - B3) + (1.0 - 1.0 / 4))) / 2.0); - else if (td < B4) - return (float) ((1.0 - (1.0/(B1*B1) * (td - B5) * (td - B5) + (1.0 - 1.0 / (4*4)))) / 2.0); - else - return (float) ((1.0 - (1.0/(B1*B1) * (td - B6) * (td - B6) + (1.0 - 1.0 / (4*4*4)))) / 2.0); - } else { - double td = t * 2.0 - 1.0; - if (td < B1) - return (float) ((1.0/(B1*B1) * td * td) / 2.0 + 0.5); - else if (td < B2) - return (float) ((1.0/(B1*B1) * (td - B3) * (td - B3) + (1.0 - 1.0 / 4)) / 2.0 + 0.5); - else if (td < B4) - return (float) ((1.0/(B1*B1) * (td - B5) * (td - B5) + (1.0 - 1.0 / (4*4))) / 2.0 + 0.5); - else - return (float) ((1.0/(B1*B1) * (td - B6) * (td - B6) + (1.0 - 1.0 / (4*4*4))) / 2.0 + 0.5); - } - } - - } -} diff --git a/Celeste.Mod.mm/Patches/Monocle/Scene.cs b/Celeste.Mod.mm/Patches/Monocle/Scene.cs index 1dbd4c382..79015e78d 100644 --- a/Celeste.Mod.mm/Patches/Monocle/Scene.cs +++ b/Celeste.Mod.mm/Patches/Monocle/Scene.cs @@ -14,16 +14,6 @@ class patch_Scene : Scene { public new event Action OnEndOfFrame; #pragma warning restore CS0414 - [MonoModReplace] - public new bool OnInterval(float interval) { - return (int) (((double) TimeActive - Engine.DeltaTime) / interval) < (int) ((double) TimeActive / interval); - } - - [MonoModReplace] - public new bool OnInterval(float interval, float offset) { - return Math.Floor(((double) TimeActive - offset - Engine.DeltaTime) / interval) < Math.Floor(((double) TimeActive - offset) / interval); - } - /// /// Finds all entities created from an EntityData with the specified SID, using the Tracker if possible. diff --git a/Celeste.Mod.mm/Patches/Monocle/SimpleCurve.cs b/Celeste.Mod.mm/Patches/Monocle/SimpleCurve.cs deleted file mode 100644 index 361f9accf..000000000 --- a/Celeste.Mod.mm/Patches/Monocle/SimpleCurve.cs +++ /dev/null @@ -1,46 +0,0 @@ -#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value - -using Microsoft.Xna.Framework; -using MonoMod; -using System.Runtime.CompilerServices; - -namespace Monocle { - // Patch XNA/FNA float jank differences - struct patch_SimpleCurve { - - public Vector2 Begin, End, Control; - - [MonoModReplace] - public void DoubleControl() { - Control = new Vector2( - (float) ((double) Control.X + Control.X - (Begin.X + ((double) End.X - Begin.X) / 2.0)), - (float) ((double) Control.Y + Control.Y - (Begin.Y + ((double) End.Y - Begin.Y) / 2.0)) - ); - } - - [MonoModReplace] - public Vector2 GetPoint(float percent) { - double num = 1.0 - percent; - return new Vector2( - (float) ((double) JITBarrier((float) (num * num)) * Begin.X + (double) JITBarrier((float) (2.0 * num * percent)) * Control.X + (double) JITBarrier((float) ((double) percent * percent)) * End.X), - (float) ((double) JITBarrier((float) (num * num)) * Begin.Y + (double) JITBarrier((float) (2.0 * num * percent)) * Control.Y + (double) JITBarrier((float) ((double) percent * percent)) * End.Y) - ); - } - - [MonoModReplace] - public float GetLengthParametric(int resolution) { - Vector2 vector = Begin; - float num = 0f; - for (int i = 1; i <= resolution; i++) { - Vector2 point = GetPoint((float) i / resolution); - num += (point - vector).Length(); - vector = point; - } - return num; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private float JITBarrier(float v) => v; - - } -} \ No newline at end of file diff --git a/Celeste.Mod.mm/Patches/Monocle/SineWave.cs b/Celeste.Mod.mm/Patches/Monocle/SineWave.cs index 9c9426f9c..a005c2c57 100755 --- a/Celeste.Mod.mm/Patches/Monocle/SineWave.cs +++ b/Celeste.Mod.mm/Patches/Monocle/SineWave.cs @@ -1,26 +1,8 @@ using MonoMod; -using System; namespace Monocle { class patch_SineWave : SineWave { - private float counter; - - public new float Value { [MonoModIgnore] get; [MonoModIgnore] private set; } - public new float ValueOverTwo { [MonoModIgnore] get; [MonoModIgnore] private set; } - public new float TwoValue { [MonoModIgnore] get; [MonoModIgnore] private set; } - - public new float Counter { - [MonoModReplace] get => counter; - [MonoModReplace] set { - // Fix TAS desyncs by patching .NET FW float jank - counter = (float) (((double) value + (double) (float) (Math.PI * 8f)) % (double) (float) (Math.PI * 8f)); - Value = (float) Math.Sin(counter); - ValueOverTwo = (float) Math.Sin(counter / 2f); - TwoValue = (float) Math.Sin(counter * 2f); - } - } - [MonoModLinkTo("Monocle.SineWave", "System.Void .ctor(System.Single,System.Single)")] [MonoModForceCall] [MonoModRemove] @@ -31,21 +13,5 @@ [MonoModReplace] set { public void ctor(float frequency) { ctor(frequency, 0f); } - - [MonoModReplace] - public new SineWave Randomize() { - // Fix TAS desyncs by patching .NET FW float jank - Counter = (float) ((double) Calc.Random.NextFloat() * (double) (float) (Math.PI * 2f) * 2.0); - return this; - } - - [MonoModReplace] - public override void Update() { - // Fix TAS desyncs by patching .NET FW float jank - Counter += (float) ((double) (float) (Math.PI * 2f) * (double) Frequency * (double) Rate * (double) (UseRawDeltaTime ? Engine.RawDeltaTime : Engine.DeltaTime)); - if (OnUpdate != null) - OnUpdate(Value); - } - } } diff --git a/Celeste.Mod.mm/Patches/Platform.cs b/Celeste.Mod.mm/Patches/Platform.cs index 98e147d0d..a3d5eca81 100644 --- a/Celeste.Mod.mm/Patches/Platform.cs +++ b/Celeste.Mod.mm/Patches/Platform.cs @@ -1,13 +1,9 @@ using Microsoft.Xna.Framework; -using MonoMod; using System; namespace Celeste { abstract class patch_Platform : Platform { - private Vector2 movementCounter = default; - internal Vector2 _movementCounter => movementCounter; // proxy for Solid patches to link against - public patch_Platform(Vector2 position, bool safe) : base(position, safe) { // no-op. MonoMod ignores this - we only need this to make the compiler shut up. @@ -17,37 +13,5 @@ public bool MoveVCollideSolidsAndBounds(Level level, float moveV, bool thruDashB return MoveVCollideSolidsAndBounds(level, moveV, thruDashBlocks, onCollide, true); } - // Patch MoveToX/Y to replicate XNA's behaviour on FNA - - [MonoModReplace] - public new void MoveToX(float toX) { - MoveH((float) ((double) toX - Position.X - movementCounter.X)); - } - - [MonoModReplace] - public new void MoveToX(float toX, float liftSpeedX) { - MoveH((float) ((double) toX - Position.X - movementCounter.X), liftSpeedX); - } - - [MonoModReplace] - public new void MoveToXNaive(float toX) { - MoveHNaive((float) ((double) toX - Position.X - movementCounter.X)); - } - - [MonoModReplace] - public new void MoveToY(float toY) { - MoveV((float) ((double) toY - Position.Y - movementCounter.Y)); - } - - [MonoModReplace] - public new void MoveToY(float toY, float liftSpeedY) { - MoveV((float) ((double) toY - Position.Y - movementCounter.Y), liftSpeedY); - } - - [MonoModReplace] - public new void MoveToYNaive(float toY) { - MoveVNaive((float) ((double) toY - Position.Y - movementCounter.Y)); - } - } } diff --git a/Celeste.Mod.mm/Patches/Player.cs b/Celeste.Mod.mm/Patches/Player.cs index 8d8d1d2bc..7fb6aae2b 100644 --- a/Celeste.Mod.mm/Patches/Player.cs +++ b/Celeste.Mod.mm/Patches/Player.cs @@ -321,27 +321,10 @@ public override void SceneEnd(Scene scene) { [PatchPlayerStarFlyReturnToNormalHitbox] private extern void StarFlyReturnToNormalHitbox(); - [MonoModIgnore] - [PatchPlayerApproachMaxMove] - public new extern IEnumerator DummyWalkTo(float x, bool walkBackwards = false, float speedMultiplier = 1f, bool keepWalkingIntoWalls = false); - - [MonoModIgnore] - [PatchPlayerApproachMaxMove] - public new extern IEnumerator DummyWalkToExact(int x, bool walkBackwards = false, float speedMultiplier = 1f, bool cancelOnFall = false); - - [MonoModIgnore] - [PatchPlayerApproachMaxMove] - private extern int DummyUpdate(); - - [MonoModIgnore] - [PatchPlayerApproachMaxMove] - private extern int NormalUpdate(); - [MonoModIgnore] [ForceNoInlining] private extern ParticleType DustParticleFromSurfaceIndex(int index); } - public static class PlayerExt { /// @@ -463,12 +446,6 @@ class PatchPlayerCtorAttribute : Attribute { } [MonoModCustomMethodAttribute(nameof(MonoModRules.PatchPlayerExplodeLaunch))] class PatchPlayerExplodeLaunchAttribute : Attribute { } - /// - /// Patches the method to fix float jank when calculationg Calc.ApproachTo maxMove values - /// - [MonoModCustomMethodAttribute(nameof(MonoModRules.PatchPlayerApproachMaxMove))] - class PatchPlayerApproachMaxMoveAttribute : Attribute { } - static partial class MonoModRules { public static void PatchPlayerOrigUpdate(ILContext context, CustomAttribute attrib) { @@ -643,36 +620,5 @@ public static void PatchPlayerExplodeLaunch(ILContext context, CustomAttribute a cursor.Emit(OpCodes.Call, m_SetPlayerWasExplodeLaunchedThisFrame); } - public static void PatchPlayerApproachMaxMove(ILContext context, CustomAttribute attrib) { - ILCursor cursor = new ILCursor(context); - while (cursor.TryGotoNext(MoveType.After, i => i.MatchCall("Monocle.Calc", "Approach"))) { - // Previous instructions must be: call Monocle.Engine::get_DeltaTime; mul - if (!cursor.Prev.Previous.MatchMul() || !cursor.Prev.Previous.Previous.MatchCall("Monocle.Engine", "get_DeltaTime")) - throw new Exception("Unexpected instructions before Calc.Approach"); - - // Patch calculation of DeltaTime multiplier - int stackDepth = 1; - for (int instrIdx = cursor.Index - 4; stackDepth > 0; instrIdx--) { - Instruction instr = context.Instrs[instrIdx]; - - if (instr.MatchAdd() || instr.MatchSub() || instr.MatchMul() || instr.MatchDiv() || instr.MatchRem()) { - // Operation instructions remain unaffected - stackDepth++; - } else if (instr.MatchLdcR4(out float v)) { - // ldc.r4 -> ...; conv.r8 - context.Instrs.Insert(instrIdx+1, Instruction.Create(OpCodes.Conv_R8)); - stackDepth--; - } else if (instr.MatchLdloc(out int idx)) { - // ldloc -> ...; conv.r8 - if (context.Body.Variables[idx].VariableType.MetadataType != MetadataType.Single) - throw new Exception($"Unexpected non-float variable load: {instr}"); - - context.Instrs.Insert(instrIdx+1, Instruction.Create(OpCodes.Conv_R8)); - stackDepth--; - } else - throw new Exception($"Unexpected instruction in DeltaTime multiplier calculation: {instr}"); - } - } - } } }