From 4ee2eba8561bb1463662bd48d95d7a83a76491a9 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 21 Jun 2026 17:50:42 +0100 Subject: [PATCH] apply correction for star positions --- MilkyWayFix/Constants.cs | 9 ++++ MilkyWayFix/GalacticPlanePatch.cs | 27 +++++----- MilkyWayFix/MilkyWayFix.cs | 2 +- MilkyWayFix/MilkyWayFix.csproj | 2 +- MilkyWayFix/ModPatch.cs | 82 +++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 MilkyWayFix/Constants.cs create mode 100644 MilkyWayFix/ModPatch.cs diff --git a/MilkyWayFix/Constants.cs b/MilkyWayFix/Constants.cs new file mode 100644 index 0000000..87e6cdc --- /dev/null +++ b/MilkyWayFix/Constants.cs @@ -0,0 +1,9 @@ +namespace MilkyWayFix; + +public static class Constants +{ + /// + /// Mean obliquity of the ecliptic at J2000 (radians) + /// + public const float EclOb = 23.439291111f * (float)KSA.Constants.DEGREES_TO_RADIANS; +} \ No newline at end of file diff --git a/MilkyWayFix/GalacticPlanePatch.cs b/MilkyWayFix/GalacticPlanePatch.cs index c67dc04..665d3cc 100644 --- a/MilkyWayFix/GalacticPlanePatch.cs +++ b/MilkyWayFix/GalacticPlanePatch.cs @@ -10,31 +10,36 @@ namespace MilkyWayFix; [HarmonyPatch(typeof(GalacticPlane))] public class GalacticPlanePatch { + /// + /// Harmony postfix to generate the correct rotation matrix so the Milky Way appears in the + /// correct orientation in the sky (using the stock skybox and shader). + /// + /// Harmony injection for the GalacticPlane instance + /// Harmony injection for the GalacticPlane._rotation private field [UsedImplicitly] [HarmonyPatch(nameof(GalacticPlane.OnDataLoad))] [HarmonyPostfix] - [SuppressMessage("ReSharper", "InconsistentNaming")] + [SuppressMessage("ReSharper", "InconsistentNaming")] // yes, rider, the four underscores are there for a reason (we love harmony) public static void OnDataLoadPostfix(GalacticPlane __instance, ref float4x4 ____rotation) { // Transform RA/dec of north galactic pole into ecliptic coordinates - const double eclOb = 23.439291111 * Constants.DEGREES_TO_RADIANS; // Mean obliquity of the ecliptic at J2000 - var ra = (double)__instance.RightAscension; - var dec = (double)__instance.Declination; - var lon = double.Atan2(double.Sin(ra) * double.Cos(eclOb) + double.Tan(dec) * double.Sin(eclOb), - double.Cos(ra)); - var lat = double.Asin(double.Sin(dec) * double.Cos(eclOb) - - double.Cos(dec) * double.Sin(eclOb) * double.Sin(ra)); + var ra = (float)__instance.RightAscension; + var dec = (float)__instance.Declination; + var lon = float.Atan2(float.Sin(ra) * float.Cos(Constants.EclOb) + float.Tan(dec) * float.Sin(Constants.EclOb), + float.Cos(ra)); + var lat = float.Asin(float.Sin(dec) * float.Cos(Constants.EclOb) - + float.Cos(dec) * float.Sin(Constants.EclOb) * float.Sin(ra)); // Rotate about Z such that the points at which the ecliptic intersects the galactic equator are along the Y axis // (This assumes that the Milky Way cubemap has the galactic centre on the positive X axis) - var preRotationZ = float4x4.CreateRotationZ(-(float)((90 - 6.38398872) * Constants.DEGREES_TO_RADIANS)); + var preRotationZ = float4x4.CreateRotationZ(-(float)((90 - 6.38398872) * KSA.Constants.DEGREES_TO_RADIANS)); // Rotate 90 degrees about Y, so the north galactic pole is facing the positive X axis var preRotationY = float4x4.CreateRotationY(-float.Pi / 2f); // Rotate by the longitude about Z, then rotate by the latitude about the transformed direction of Y - var raRotation = float4x4.CreateRotationZ((float)lon); + var raRotation = float4x4.CreateRotationZ(lon); var rotatedYAxis = raRotation * float4.UnitY; - var decRotation = float4x4.CreateFromAxisAngle(rotatedYAxis.XYZ, (float)lat); + var decRotation = float4x4.CreateFromAxisAngle(rotatedYAxis.XYZ, lat); ____rotation = decRotation * raRotation * preRotationY * preRotationZ; } } \ No newline at end of file diff --git a/MilkyWayFix/MilkyWayFix.cs b/MilkyWayFix/MilkyWayFix.cs index dcb6bf6..baedee8 100644 --- a/MilkyWayFix/MilkyWayFix.cs +++ b/MilkyWayFix/MilkyWayFix.cs @@ -13,7 +13,7 @@ public class MilkyWayFix [UsedImplicitly] [StarMapBeforeMain] - [SuppressMessage("Performance", "CA1822:Mark members as static")] + [SuppressMessage("Performance", "CA1822:Mark members as static")] // StarMap hooks must be non-static public void FullyLoaded() { Harmony.PatchAll(typeof(MilkyWayFix).Assembly); diff --git a/MilkyWayFix/MilkyWayFix.csproj b/MilkyWayFix/MilkyWayFix.csproj index 171d71d..166c2ab 100644 --- a/MilkyWayFix/MilkyWayFix.csproj +++ b/MilkyWayFix/MilkyWayFix.csproj @@ -7,7 +7,7 @@ - 0.1.0 + 0.2.0 diff --git a/MilkyWayFix/ModPatch.cs b/MilkyWayFix/ModPatch.cs new file mode 100644 index 0000000..023b240 --- /dev/null +++ b/MilkyWayFix/ModPatch.cs @@ -0,0 +1,82 @@ +using System.Reflection.Emit; +using System.Security.Cryptography; +using Brutal.Numerics; +using HarmonyLib; +using JetBrains.Annotations; +using KSA; + +namespace MilkyWayFix; + +[UsedImplicitly] +[HarmonyPatch(typeof(Mod))] +public class ModPatch +{ + /// + /// SHA256 hash of the stock star binary (Content/Core/hip_main.bin as of 2026.6.8.4680). + /// + private const string StockBinaryHash = "f6e4edb59cfc38947be1b81a8f9f16abcf3b014a957d48138e84c81713cb4f20"; + + /// + /// Check whether a FileStream is the stock star binary by comparing its SHA-256 hash. + /// + /// (We only want to apply corrections to the stock star binary; if the user has replaced the star binary + /// with a custom one, it is assumed to already be in the correct (ecliptic) coordinate system.) + /// + /// FileStream of the star binary to check + /// True if the FileStream is the stock star binary, false otherwise + [UsedImplicitly] + private static bool IsStockStarBinary(FileStream stream) + { + stream.Position = 0; + using var sha256 = SHA256.Create(); + var hash = sha256.ComputeHash(stream); + stream.Position = 0; + + var hashString = Convert.ToHexStringLower(hash); + return hashString == StockBinaryHash; + } + + /// + /// Correct the given star coordinates so the star appears in the right place in the sky. + /// This is achieved by swapping the Y and Z axes, then transforming from equatorial to ecliptic coordinates. + /// + /// The star coordinates to correct. Should be a unit vector. + /// If this parameter is false, this method simply returns coords unchanged. + /// + [UsedImplicitly] + private static float3 FixStarCoordinates(float3 coords, bool fix) + { + if (!fix) return coords; + + return new float3(coords.X, + float.Cos(Constants.EclOb) * coords.Z + float.Sin(Constants.EclOb) * coords.Y, + -float.Sin(Constants.EclOb) * coords.Z + float.Cos(Constants.EclOb) * coords.Y); + } + + /// + /// Harmony transpiler for Mod.LoadStarBinaries, which applies the correction above to all stars + /// in the stock star binary. + /// + [UsedImplicitly] + [HarmonyPatch(nameof(Mod.LoadStarBinaries))] + [HarmonyTranspiler] + public static IEnumerable LoadStarBinariesTranspiler(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + matcher.MatchStartForward(CodeMatch.Calls(() => File.OpenRead(null!))) + .ThrowIfInvalid("Could not find File.OpenRead() call") + .DeclareLocal(typeof(bool), out var localIsStockStarBinary) + .InsertAfterAndAdvance( + new CodeInstruction(OpCodes.Dup), + CodeInstruction.Call(() => IsStockStarBinary(null!)), + CodeInstruction.StoreLocal(localIsStockStarBinary.LocalIndex) + ) + .MatchStartForward(CodeMatch.Calls(() => float3.Normalize(default))) + .ThrowIfInvalid("Could not find float3.Normalize() call") + .InsertAfterAndAdvance( + CodeInstruction.LoadLocal(localIsStockStarBinary.LocalIndex), + CodeInstruction.Call(() => FixStarCoordinates(default, false))); + + return matcher.Instructions(); + } +} \ No newline at end of file -- 2.51.2