From 50d52fb25e207d0c7a7457da9bfa8b09d3d54add Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Thu, 2 Mar 2023 19:29:57 -0800 Subject: [PATCH] fix: Makes gump type id stable (#1358) --- Projects/Server/Gumps/Gump.cs | 10 ++++- Projects/Server/Utilities/HashUtility.cs | 54 ++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Projects/Server/Gumps/Gump.cs b/Projects/Server/Gumps/Gump.cs index 3439f2a12..5c1426e1e 100644 --- a/Projects/Server/Gumps/Gump.cs +++ b/Projects/Server/Gumps/Gump.cs @@ -81,7 +81,15 @@ public partial class Gump public bool Closable { get; set; } = true; - public static int GetTypeID(Type type) => type?.FullName?.GetHashCode(StringComparison.Ordinal) ?? -1; + public static int GetTypeID(Type type) + { + unchecked + { + // To use the original .NET Framework deterministic hash code (with really bad performance) + // change the next line to use HashUtility.GetNetFrameworkHashCode + return (int)HashUtility.ComputeHash32(type?.FullName); + } + } public void AddPage(int page) { diff --git a/Projects/Server/Utilities/HashUtility.cs b/Projects/Server/Utilities/HashUtility.cs index e757c5140..0f2716250 100644 --- a/Projects/Server/Utilities/HashUtility.cs +++ b/Projects/Server/Utilities/HashUtility.cs @@ -14,6 +14,7 @@ *************************************************************************/ using System; +using System.Numerics; using System.Runtime.CompilerServices; using Standart.Hash.xxHash; @@ -25,7 +26,8 @@ namespace Server; public enum FastHashAlgorithm { None, // Used for collisions where full-data is serialized instead - XXHash3_64, // xxHash3 64bit + XxHash3_64, // xxHash3 64bit + XxHash_32, // xxHash 32bit } public static class HashUtility @@ -34,15 +36,61 @@ public static class HashUtility // * Computed hashes might be serialized against this seed! * // ********************************************************** private const ulong xxHash3Seed = 9609125370673258709ul; // Randomly generated 64-bit prime number + private const uint xxHash1Seed = 665738807u; // Randomly generated 32-bit prime number [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong ComputeHash64(string? data, FastHashAlgorithm algorithm = FastHashAlgorithm.XXHash3_64) => + public static ulong ComputeHash64(string? data, FastHashAlgorithm algorithm = FastHashAlgorithm.XxHash3_64) => algorithm switch { - FastHashAlgorithm.XXHash3_64 => ComputeXXHash3_64(data), + FastHashAlgorithm.XxHash3_64 => ComputeXXHash3_64(data), _ => throw new NotSupportedException($"Hash {algorithm} is not supported.") }; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ComputeXXHash3_64(string? data) => data == null ? 0 : xxHash3.ComputeHash(data, xxHash3Seed); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ComputeHash32(string? data, FastHashAlgorithm algorithm = FastHashAlgorithm.XxHash_32) => + algorithm switch + { + FastHashAlgorithm.XxHash_32 => ComputeXXHash_32(data), + _ => throw new NotSupportedException($"Hash {algorithm} is not supported.") + }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ComputeXXHash_32(string? data) => data == null ? 0 : xxHash32.ComputeHash(data, xxHash1Seed); + + public static unsafe int GetNetFrameworkHashCode(this string? str) + { + if (str == null) + { + return 0; + } + + fixed (char* src = &str.GetPinnableReference()) + { + uint hash1 = (5381 << 16) + 5381; + uint hash2 = hash1; + + uint* ptr = (uint*)src; + int length = str.Length; + + while (length > 2) + { + length -= 4; + // Where length is 4n-1 (e.g. 3,7,11,15,19) this additionally consumes the null terminator + hash1 = (BitOperations.RotateLeft(hash1, 5) + hash1) ^ ptr[0]; + hash2 = (BitOperations.RotateLeft(hash2, 5) + hash2) ^ ptr[1]; + ptr += 2; + } + + if (length > 0) + { + // Where length is 4n-3 (e.g. 1,5,9,13,17) this additionally consumes the null terminator + hash2 = (BitOperations.RotateLeft(hash2, 5) + hash2) ^ ptr[0]; + } + + return (int)(hash1 + hash2 * 1566083941); + } + } }