Skip to content

Commit 3f76823

Browse files
authored
Detect and correct some localization key hash collisions (#2493) #patch
1 parent 66fb892 commit 3f76823

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

ImperatorToCK3/CK3/CK3LocDB.cs

+23
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using commonItems.Localization;
44
using commonItems.Mods;
55
using ImperatorToCK3.CK3.Localization;
6+
using Murmur;
67
using System.Collections.Generic;
78
using System.IO;
89
using System.Linq;
@@ -83,6 +84,15 @@ public CK3LocBlock GetOrCreateLocBlock(string id) {
8384
return locBlock;
8485
}
8586

87+
// Check for hash collision.
88+
var murmur3A = MurmurHash.Create32();
89+
var hashStr = GetHashStrForKey(murmur3A, id);
90+
if (hashToKeyDict.TryGetValue(hashStr, out var existingKey)) {
91+
Logger.Warn($"Hash collision detected for loc key: {id}. Existing key: {existingKey}");
92+
} else {
93+
hashToKeyDict[hashStr] = id;
94+
}
95+
8696
// Create new loc block.
8797
locBlock = new CK3LocBlock(id, ConverterGlobals.PrimaryLanguage);
8898
Add(locBlock);
@@ -144,4 +154,17 @@ public List<string> GetLocLinesToOutputForLanguage(string language) {
144154

145155
return locLinesToOutput;
146156
}
157+
158+
public bool KeyHasConflictingHash(string key) {
159+
var murmur3A = MurmurHash.Create32();
160+
return hashToKeyDict.ContainsKey(GetHashStrForKey(murmur3A, key));
161+
}
162+
163+
private string GetHashStrForKey(Murmur32 murmur32, string key) {
164+
var keyBytes = System.Text.Encoding.UTF8.GetBytes(key);
165+
var hash = murmur32.ComputeHash(keyBytes);
166+
return string.Join("", hash.Select(b => b.ToString("X2")));
167+
}
168+
169+
private readonly Dictionary<string, string> hashToKeyDict = new(); // stores MurmurHash3A hash to key mapping
147170
}

ImperatorToCK3/CK3/Dynasties/Dynasty.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ public Dynasty(Family irFamily, CharacterCollection irCharacters, CulturesDB irC
3939

4040
public Dynasty(CK3.Characters.Character character, string irFamilyName, ImperatorCharacter[] irMembers, CulturesDB irCulturesDB, LocDB irLocDB, CK3LocDB ck3LocDB, Date date) {
4141
FromImperator = true;
42-
Id = $"dynn_irtock3_from_{character.Id}";
42+
43+
string id = $"dynn_irtock3_from_{character.Id}";
44+
uint counter = 0;
45+
while (ck3LocDB.KeyHasConflictingHash(id)) {
46+
id = $"dynn_irtock3_from_{character.Id}_{counter++}";
47+
}
48+
Id = id;
4349
Name = Id;
4450

4551
CultureId = character.GetCultureId(date) ?? character.Father?.GetCultureId(date);

ImperatorToCK3/ImperatorToCK3.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<PrivateAssets>all</PrivateAssets>
4343
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
4444
</PackageReference>
45+
<PackageReference Include="MurmurHash.NETStandard" Version="1.0.0" />
4546
<PackageReference Include="PGCG.commonItems" Version="15.1.6" />
4647
<PackageReference Include="PGCG.commonItems.SourceGenerators" Version="1.0.8"/>
4748
<PackageReference Include="Polly" Version="8.5.2" />

0 commit comments

Comments
 (0)