Editor/HumanoidRetargeter/Embedded/ValveResourceFormat/Utils/StringToken.cs
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using HumanoidRetargeterVrf.Utils;
using System.Collections.Concurrent;
using HumanoidRetargeterVrf.ThirdParty;
namespace HumanoidRetargeterVrf.Utils
{
/// <summary>
/// Provides utilities for string token hashing and inverse lookup.
/// </summary>
public static class StringToken
{
#if VRF_NO_GENERATOR_VERSION
// Use the following command to avoid putting version in the dumps for stable git tracking of dumped files
// dotnet build -p:DefineConstants=VRF_NO_GENERATOR_VERSION
/// <summary>
/// Generator identification string.
/// </summary>
public const string VRF_GENERATOR = $"Source 2 Viewer - https://valveresourceformat.github.io";
#else
private static readonly string ProductVersionString = typeof(StringToken).Assembly.GetName().Version!.ToString();
/// <summary>
/// Generator identification string with version.
/// </summary>
public static readonly string VRF_GENERATOR = $"Source 2 Viewer {ProductVersionString} - https://valveresourceformat.github.io";
#endif
/// <summary>
/// MurmurHash2 seed value.
/// </summary>
public const uint MURMUR2SEED = 0x31415926; // It's pi!
/// <summary>
/// Gets the inverted table for hash to string lookups.
/// </summary>
public static readonly ConcurrentDictionary<uint, string> InvertedTable = new(InitializeInverseLookup());
/// <summary>
/// Computes the hash token for the given string.
/// </summary>
/// <param name="key">The string to hash.</param>
/// <returns>The hash token.</returns>
public static uint Get(string key) => MurmurHash2.Hash(key, MURMUR2SEED);
/// <summary>
/// Gets a known string for the given hash, or returns an unknown key placeholder.
/// </summary>
/// <param name="hash">The hash to look up.</param>
/// <returns>The known string or a placeholder.</returns>
public static string GetKnownString(uint hash)
{
if (InvertedTable.TryGetValue(hash, out var knownString))
{
return knownString;
}
return $"vrf_unknown_key_{hash}";
}
/// <summary>
/// Store a string to the table of known string hashes, so it can later be retrieved using <see cref="GetKnownString"/>.
/// </summary>
public static uint Store(string key)
{
var token = Get(key.ToLowerInvariant());
InvertedTable[token] = key;
return token;
}
/// <summary>
/// Store a number of strings to the table of known string hashes, so they can later be retrieved using <see cref="GetKnownString"/>.
/// </summary>
public static void Store(IEnumerable<string> keys)
{
foreach (var key in keys)
{
Store(key);
}
}
internal static Dictionary<uint, string> InitializeInverseLookup()
{
var inverseLookup = new Dictionary<uint, string>(EntityLumpKnownKeys.KnownKeys.Length);
foreach (var key in EntityLumpKnownKeys.KnownKeys)
{
var token = MurmurHash2.Hash(key, MURMUR2SEED);
inverseLookup.Add(token, key);
}
return inverseLookup;
}
}
}