Skip to content

Commit df7b8d6

Browse files
committed
Improve cache ID to fix cache collisions, backwards compatible
1 parent 3826e3b commit df7b8d6

File tree

4 files changed

+52
-8
lines changed

4 files changed

+52
-8
lines changed

Shared_QuickAccessBox/ItemInfo.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ public ItemInfo(int groupNo, int categoryNo, int localSlot, Info.ItemLoadInfo st
3636
GUID = zipmodInfo.GUID;
3737
ZipmodSlot = zipmodInfo.Slot;
3838
DeveloperSearchString += "\v" + ZipmodSlot;
39-
NewCacheId = MakeNewCacheId(groupNo, categoryNo, ZipmodSlot);
39+
NewCacheId = MakeNewCacheId(groupNo, categoryNo, ZipmodSlot, zipmodInfo.GUID);
40+
NewCacheIdShort = MakeNewCacheId(groupNo, categoryNo, ZipmodSlot, null);
4041
}
4142
else
4243
{
4344
ZipmodSlot = -1;
44-
NewCacheId = MakeNewCacheId(groupNo, categoryNo, LocalSlot);
45+
NewCacheId = NewCacheIdShort = MakeNewCacheId(groupNo, categoryNo, LocalSlot, null);
4546
}
4647

4748
if (zipmodFilename != null)
@@ -165,6 +166,11 @@ public ItemInfo(int groupNo, int categoryNo, int localSlot, Info.ItemLoadInfo st
165166
[Obsolete("Will be removed", true)]
166167
public string CacheId => OldCacheId;
167168
internal string NewCacheId { get; }
169+
/// <summary>
170+
/// Only for backwards compatibility, turns out the ID wasn't unique across zipmods
171+
/// </summary>
172+
[Obsolete]
173+
internal string NewCacheIdShort { get; }
168174
[Obsolete]
169175
internal string OldCacheId { get; }
170176

@@ -202,7 +208,7 @@ public void AddItem()
202208
// Some modded items crash in Studio.OCIItem.UpdateColor()
203209
}
204210
}
205-
211+
206212
private void UpdateCompositeStrings()
207213
{
208214
FullName = GroupName + "/" + CategoryName + "/" + ItemName;
@@ -221,10 +227,13 @@ private void UpdateCompositeStrings()
221227
SearchString = searchStr.Replace(' ', '_').ToLowerInvariant();
222228
}
223229

224-
private static string MakeNewCacheId(int groupNo, int categoryNo, int slotNo)
230+
private static string MakeNewCacheId(int groupNo, int categoryNo, int slotNo, string guid)
225231
{
226232
// Sideloader generated local slot numbers start at 100000000, so real slot numbers should have at most 8 digits
227-
return $"{groupNo:D8}-{categoryNo:D8}-{slotNo:D8}";
233+
var str = $"{groupNo:D8}-{categoryNo:D8}-{slotNo:D8}";
234+
if (guid != null)
235+
str += $"-{Utils.GetHashCode(guid):X8}"; // Pretty much the same as using full guid string. Trimming hash to 4 bytes causes a lot of collisions.
236+
return str;
228237
}
229238

230239
[Obsolete]
@@ -256,7 +265,7 @@ public string ToDescriptionString()
256265

257266
var sb = new StringBuilder();
258267
sb.AppendLine(FullName);
259-
268+
260269
sb.Append($"Group = {GroupNo} Category = {CategoryNo}");
261270
if (isZipmod) sb.Append($" LocalSlot = {LocalSlot} ZipmodSlot = {ZipmodSlot}");
262271
else sb.Append($" Slot = {LocalSlot}");

Shared_QuickAccessBox/ItemInfoLoader.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
5+
using System.Linq;
56
using System.Reflection;
67
using System.Timers;
78
using BepInEx;
@@ -95,6 +96,13 @@ public static void LoadItems()
9596
results.Sort((x, y) => string.Compare(x.FullName, y.FullName, StringComparison.Ordinal));
9697
ItemList = results;
9798

99+
#if DEBUG
100+
#pragma warning disable CS0612
101+
var oldGroups = results.GroupBy(x => x.OldCacheId).Count(x => x.Count() > 1);
102+
#pragma warning restore CS0612
103+
var nowGroups = results.GroupBy(x => x.NewCacheId).Count(x => x.Count() > 1);
104+
QuickAccessBox.Logger.LogInfo($"Cache collisions: old={oldGroups} new={nowGroups}");
105+
#endif
98106
}
99107

100108
private static void LoadTranslationCache()

Shared_QuickAccessBox/ThumbnailCache.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ public static Sprite GetThumbnail(ItemInfo info)
3737
}
3838
}
3939

40-
_pngNameCache.TryGetValue(info.OldCacheId, out var pngPath);
40+
_pngNameCache.TryGetValue(info.NewCacheId, out var pngPath);
4141
if (pngPath == null)
4242
{
4343
// Fall back to old thumbnail names in case the mod wasn't updated
4444
#pragma warning disable CS0612
45-
_pngNameCache.TryGetValue(info.NewCacheId, out pngPath);
45+
_pngNameCache.TryGetValue(info.OldCacheId, out pngPath);
4646
#pragma warning restore CS0612
47+
if (pngPath == null)
48+
_pngNameCache.TryGetValue(info.NewCacheIdShort, out pngPath);
4749
}
4850

4951
var tex = Sideloader.Sideloader.GetPng(pngPath, TextureFormat.DXT5, false);

Shared_QuickAccessBox/Utils.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,30 @@ public static string MakeValidFileName(string text, char? replacement = '_', boo
6363

6464
public static bool IsFavorited(this ItemInfo item) => QuickAccessBox.Instance.Favorited.Check(item.GUID, item.NewCacheId);
6565
public static bool IsBlacklisted(this ItemInfo item) => QuickAccessBox.Instance.Blacklisted.Check(item.GUID, item.NewCacheId);
66+
67+
/// <summary>
68+
/// Repatable hash code for strings, not framework implementation dependent.
69+
/// </summary>
70+
public static unsafe int GetHashCode(string str)
71+
{
72+
fixed (char* chPtr = str)
73+
{
74+
int num1 = 352654597;
75+
int num2 = num1;
76+
int* numPtr = (int*)chPtr;
77+
for (int length = str.Length; length > 0; length -= 4)
78+
{
79+
num1 = (num1 << 5) + num1 + (num1 >> 27) ^ *numPtr;
80+
if (length > 2)
81+
{
82+
num2 = (num2 << 5) + num2 + (num2 >> 27) ^ numPtr[1];
83+
numPtr += 2;
84+
}
85+
else
86+
break;
87+
}
88+
return num1 + num2 * 1566083941;
89+
}
90+
}
6691
}
6792
}

0 commit comments

Comments
 (0)