From 013d524544ecdb128b172fd30cdcab8522800153 Mon Sep 17 00:00:00 2001 From: MDietermann Date: Mon, 1 Jun 2026 15:20:09 +0200 Subject: [PATCH] feat(world-gen): add WormHash deterministic mixing function --- VoxelEngine.Tests/WorldGen/WormHashTests.cs | 40 +++++++++++++++++++++ VoxelEngine.csproj | 4 +++ World/WorldGen/WormHash.cs | 21 +++++++++++ 3 files changed, 65 insertions(+) create mode 100644 VoxelEngine.Tests/WorldGen/WormHashTests.cs create mode 100644 World/WorldGen/WormHash.cs diff --git a/VoxelEngine.Tests/WorldGen/WormHashTests.cs b/VoxelEngine.Tests/WorldGen/WormHashTests.cs new file mode 100644 index 0000000..b439e2f --- /dev/null +++ b/VoxelEngine.Tests/WorldGen/WormHashTests.cs @@ -0,0 +1,40 @@ +using VoxelEngine.World.WorldGen; +using Xunit; + +namespace VoxelEngine.Tests.WorldGen; + +public class WormHashTests +{ + [Fact] + public void Hash_IsDeterministic_ForSameInputs() + { + uint a = WormHash.Hash(3, -2, 7, seed: 1337); + uint b = WormHash.Hash(3, -2, 7, seed: 1337); + Assert.Equal(a, b); + } + + [Fact] + public void Hash_DiffersForDifferentCells() + { + uint a = WormHash.Hash(3, -2, 7, seed: 1337); + uint b = WormHash.Hash(3, -2, 8, seed: 1337); + Assert.NotEqual(a, b); + } + + [Fact] + public void Hash_DiffersForDifferentSeeds() + { + uint a = WormHash.Hash(3, -2, 7, seed: 1337); + uint b = WormHash.Hash(3, -2, 7, seed: 9999); + Assert.NotEqual(a, b); + } + + [Fact] + public void Hash_HandlesNegativeCoords() + { + // Just shouldn't throw and shouldn't collide trivially with the positive case. + uint a = WormHash.Hash(-1, -1, -1, seed: 1); + uint b = WormHash.Hash(1, 1, 1, seed: 1); + Assert.NotEqual(a, b); + } +} diff --git a/VoxelEngine.csproj b/VoxelEngine.csproj index 49ccd2e..207888a 100644 --- a/VoxelEngine.csproj +++ b/VoxelEngine.csproj @@ -22,4 +22,8 @@ + + + + diff --git a/World/WorldGen/WormHash.cs b/World/WorldGen/WormHash.cs new file mode 100644 index 0000000..5a946f4 --- /dev/null +++ b/World/WorldGen/WormHash.cs @@ -0,0 +1,21 @@ +namespace VoxelEngine.World.WorldGen; + +// Deterministic 32-bit mixing hash for worm-cell coordinates. +// Cell coords can be negative; cast through unchecked to preserve bit pattern. +internal static class WormHash +{ + public static uint Hash(int cellX, int cellY, int cellZ, int seed) + { + unchecked + { + uint h = (uint)seed; + h ^= (uint)cellX * 73856093u; + h ^= (uint)cellY * 19349663u; + h ^= (uint)cellZ * 83492791u; + h ^= h >> 13; + h *= 0x5bd1e995u; + h ^= h >> 15; + return h; + } + } +}