using System.Numerics; using System.Runtime.CompilerServices; namespace AcDream.Core.Tests.Terrain; /// /// Faithful C# port of the original AC client terrain algorithms, /// translated from decompiled C++ in acclient-source-split/CLandBlockStruct.cpp. /// Serves as the ground-truth oracle for conformance testing. /// /// Ported from WorldBuilder-ACME-Edition/WorldBuilder.Tests/ClientReference.cs. /// All formulas use signed int arithmetic with unchecked wrapping to match x86 behavior. /// public static class ClientReference { /// /// Port of CLandBlockStruct::ConstructPolygons at offset 0x00531D10. /// Returns true when the triangle split goes from SW to NE (SWtoNEcut=1). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsSWtoNECut(int globalCellX, int globalCellY) { unchecked { int v7 = globalCellY * (214614067 * globalCellX + 1813693831) - 1109124029 * globalCellX - 1369149221; return (double)(uint)v7 * 2.3283064e-10 >= 0.5; } } /// /// Port of pal_code[0] from CLandBlockStruct::GetCellRotation at offset 0x00532170. /// Corner order: 0=(ix,iy), 1=(ix+1,iy), 2=(ix+1,iy+1), 3=(ix,iy+1) /// public static uint GetPalCode( int r0, int t0, int r1, int t1, int r2, int t2, int r3, int t3, int texSize = 1) { unchecked { return (uint)(t3 + (texSize << 28) + 32 * (t2 + 32 * (t1 + 32 * (t0 + 32 * (r3 + 4 * (r2 + 4 * (r1 + 4 * r0))))))); } } /// /// Port of CLandBlockStruct::ConstructVertices at offset 0x005328D0. /// Height = LandDefs::Land_Height_Table[height_byte] /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetVertexHeight(float[] landHeightTable, byte heightByte) { return landHeightTable[heightByte]; } /// /// Port of CLandBlockStruct::ConstructVertices vertex position. /// Each vertex is at (ix * polySize, iy * polySize, height). /// public static Vector3 GetVertexPosition(float[] landHeightTable, byte heightByte, int ix, int iy, float polySize = 24f) { return new Vector3(ix * polySize, iy * polySize, landHeightTable[heightByte]); } public const int MapWidth = 255; public const int MapHeight = 255; public const float CellSize = 24.0f; public const int CellsPerBlock = 8; public const float RoadWidth = 5.0f; public const float BlockLength = 192.0f; }