diff --git a/PKHeX.Core/Saves/Access/SCBlockAccessor.cs b/PKHeX.Core/Saves/Access/SCBlockAccessor.cs
index 8be6a270d..bf5fa8374 100644
--- a/PKHeX.Core/Saves/Access/SCBlockAccessor.cs
+++ b/PKHeX.Core/Saves/Access/SCBlockAccessor.cs
@@ -1,87 +1,92 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
-namespace PKHeX.Core
+namespace PKHeX.Core;
+
+///
+/// block accessor, where blocks are ordered by ascending .
+///
+public abstract class SCBlockAccessor : ISaveBlockAccessor
{
+ public abstract IReadOnlyList BlockInfo { get; }
+
+ ///
+ public object GetBlockValue(uint key) => GetBlock(key).GetValue();
+
+ ///
+ public void SetBlockValue(uint key, object value) => GetBlock(key).SetValue(value);
+
+ /// Checks if there is any with the requested .
+ public bool HasBlock(uint key) => FindIndex(BlockInfo, key) != -1;
+
+ /// Returns the reference with the corresponding .
+ public SCBlock GetBlock(uint key) => Find(BlockInfo, key);
+
+ #region Ease of Use Overloads
+ ///
+ /// Block name (un-hashed)
+ public SCBlock GetBlock(string name) => GetBlock(Hash(name.AsSpan()));
+
+ ///
+ public SCBlock GetBlock(ReadOnlySpan name) => GetBlock(Hash(name));
+ private static uint Hash(ReadOnlySpan name) => (uint)FnvHash.HashFnv1a_64(name);
+
+ ///
+ public SCBlock GetBlock(ReadOnlySpan name) => GetBlock(Hash(name));
+ private static uint Hash(ReadOnlySpan name) => (uint)FnvHash.HashFnv1a_64(name);
+ #endregion
+
///
- /// block accessor, where blocks are ordered by ascending .
+ /// Tries to grab the actual block, and returns a new dummy if the block does not exist.
///
- public abstract class SCBlockAccessor : ISaveBlockAccessor
+ /// Block Key
+ /// Block if exists, dummy if not. Dummy key will not match requested key.
+ public SCBlock GetBlockSafe(uint key) => FindOrDefault(BlockInfo, key);
+
+ private static SCBlock Find(IReadOnlyList array, uint key)
{
- public abstract IReadOnlyList BlockInfo { get; }
+ var index = FindIndex(array, key);
+ if (index != -1)
+ return array[index];
+ throw new KeyNotFoundException(nameof(key));
+ }
- public object GetBlockValue(uint key) => GetBlock(key).GetValue();
- public void SetBlockValue(uint key, object value) => GetBlock(key).SetValue(value);
- public bool HasBlock(uint key) => FindIndex(BlockInfo, key) != -1;
+ private static SCBlock FindOrDefault(IReadOnlyList array, uint key)
+ {
+ var index = FindIndex(array, key);
+ if (index != -1)
+ return array[index];
+ return new SCBlock(0, SCTypeCode.None);
+ }
- // Rather than storing a dictionary of keys, we can abuse the fact that the SCBlock[] is stored in order of ascending block key.
- // Binary Search doesn't require extra memory like a Dictionary would; also, we only need to find a few blocks.
- public SCBlock GetBlock(uint key) => BinarySearch(BlockInfo, key);
-
- ///
- /// Tries to grab the actual block, and returns a new dummy if the block does not exist.
- ///
- /// Block Key
- /// Block if exists, dummy if not. Dummy key will not match requested key.
- public SCBlock GetBlockSafe(uint key) => BinarySearchSafe(BlockInfo, key);
-
- private static SCBlock BinarySearch(IReadOnlyList arr, uint key)
+ ///
+ /// Finds a specified within the .
+ ///
+ ///
+ /// Rather than storing a dictionary of keys, we can abuse the fact that the is stored in order of ascending block key.
+ ///
+ /// Binary Search doesn't require extra memory like a Dictionary would; also, we usually only need to find a few blocks.
+ ///
+ /// Index-able collection
+ /// to find.
+ /// Returns -1 if no match found.
+ private static int FindIndex(IReadOnlyList array, uint key)
+ {
+ int min = 0;
+ int max = array.Count - 1;
+ do
{
- int min = 0;
- int max = arr.Count - 1;
- do
- {
- int mid = (min + max) / 2;
- var entry = arr[mid];
- var ek = entry.Key;
- if (key == ek)
- return entry;
+ int mid = min + ((max - min) >> 1);
+ var entry = array[mid];
+ var ek = entry.Key;
+ if (key == ek)
+ return mid;
- if (key < ek)
- max = mid - 1;
- else
- min = mid + 1;
- } while (min <= max);
- throw new KeyNotFoundException(nameof(key));
- }
-
- private static SCBlock BinarySearchSafe(IReadOnlyList arr, uint key)
- {
- int min = 0;
- int max = arr.Count - 1;
- do
- {
- int mid = (min + max) / 2;
- var entry = arr[mid];
- var ek = entry.Key;
- if (key == ek)
- return entry;
-
- if (key < ek)
- max = mid - 1;
- else
- min = mid + 1;
- } while (min <= max);
- return new SCBlock(0, SCTypeCode.None);
- }
-
- private static int FindIndex(IReadOnlyList arr, uint key)
- {
- int min = 0;
- int max = arr.Count - 1;
- do
- {
- int mid = (min + max) / 2;
- var entry = arr[mid];
- var ek = entry.Key;
- if (key == ek)
- return mid;
-
- if (key < ek)
- max = mid - 1;
- else
- min = mid + 1;
- } while (min <= max);
- return -1;
- }
+ if (key < ek)
+ max = mid - 1;
+ else
+ min = mid + 1;
+ } while (min <= max);
+ return -1;
}
}
diff --git a/PKHeX.Core/Saves/Encryption/SwishCrypto/FnvHash.cs b/PKHeX.Core/Saves/Encryption/SwishCrypto/FnvHash.cs
index 7215db485..40a294531 100644
--- a/PKHeX.Core/Saves/Encryption/SwishCrypto/FnvHash.cs
+++ b/PKHeX.Core/Saves/Encryption/SwishCrypto/FnvHash.cs
@@ -1,22 +1,23 @@
-using System.Collections.Generic;
+using System;
namespace PKHeX.Core;
///
/// Fowler–Noll–Vo non-cryptographic hash
///
+/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
public static class FnvHash
{
private const ulong kFnvPrime_64 = 0x00000100000001b3;
private const ulong kOffsetBasis_64 = 0xCBF29CE484222645;
///
- /// Gets the hash code of the input sequence via the default Fnv1 method.
+ /// Gets the hash code of the input sequence via the alternative Fnv1 method.
///
/// Input sequence
/// Initial hash value
/// Computed hash code
- public static ulong HashFnv1a_64(IEnumerable input, ulong hash = kOffsetBasis_64)
+ public static ulong HashFnv1a_64(ReadOnlySpan input, ulong hash = kOffsetBasis_64)
{
foreach (var c in input)
{
@@ -32,7 +33,7 @@ public static ulong HashFnv1a_64(IEnumerable input, ulong hash = kOffsetBa
/// Input sequence
/// Initial hash value
/// Computed hash code
- public static ulong HashFnv1a_64(IEnumerable input, ulong hash = kOffsetBasis_64)
+ public static ulong HashFnv1a_64(ReadOnlySpan input, ulong hash = kOffsetBasis_64)
{
foreach (var c in input)
{
diff --git a/PKHeX.Core/Saves/SAV8SWSH.cs b/PKHeX.Core/Saves/SAV8SWSH.cs
index 3cef76b23..175812a0c 100644
--- a/PKHeX.Core/Saves/SAV8SWSH.cs
+++ b/PKHeX.Core/Saves/SAV8SWSH.cs
@@ -209,6 +209,7 @@ public void UnlockAllDiglett()
if (SaveRevision == 0)
return; // no blocks
+ // Zone specific values
(int Zone, int Max)[] zones =
{
(0201, 16), // Fields of Honor
@@ -229,33 +230,36 @@ public void UnlockAllDiglett()
(0231, 9), // Honeycalm Island
};
var s = Blocks;
- static uint Hash(string str) => (uint)FnvHash.HashFnv1a_64(str);
foreach (var (zone, max) in zones)
{
var baseName = $"z_wr{zone:0000}_F_DHIGUDA";
- s.GetBlock(Hash(baseName)).ChangeBooleanType(SCTypeCode.Bool2);
+ s.GetBlock(baseName).ChangeBooleanType(SCTypeCode.Bool2);
for (int i = 0; i <= max; i++)
{
var otherName = $"{baseName}_{i}";
- s.GetBlock(Hash(otherName)).ChangeBooleanType(SCTypeCode.Bool2);
+ s.GetBlock(otherName).ChangeBooleanType(SCTypeCode.Bool2);
}
var countName = $"WK_EV_R1_DHIG_WR{zone:0000}";
var value = max + 2;
if (zone == 0223) // trio
- value++;
- s.GetBlock(Hash(countName)).SetValue((uint)value);
+ value += 2;
+ s.GetBlock(countName).SetValue((uint)value);
}
- const string TRIO = "z_wr0223_F_TRIO";
- s.GetBlock(Hash(TRIO)).ChangeBooleanType(SCTypeCode.Bool2);
+ // Atypical named values
+ const string TRIO1 = "z_wr0223_F_TRIO";
+ const string TRIO2 = "FE_R1_DHIGUDA_TRIO";
+ s.GetBlock(TRIO1).ChangeBooleanType(SCTypeCode.Bool2);
+ s.GetBlock(TRIO2).ChangeBooleanType(SCTypeCode.Bool2);
+ // Overall named values
const string unreported = "WK_EV_R1_DHIGUDA_ADD";
const string totalCount = "WK_EV_R1_DHIGUDA_COUNT";
const string progressCt = "WK_EV_R1_DHIGUDA_PROGRESS";
- s.GetBlock(Hash(unreported)).SetValue((uint)0); // none unreported
- s.GetBlock(Hash(totalCount)).SetValue((uint)150); // all obtained count
- s.GetBlock(Hash(progressCt)).SetValue((uint)11); // all obtained progress value
+ s.GetBlock(unreported).SetValue((uint)150); // 150 unreported
+ s.GetBlock(totalCount).SetValue((uint)1); // obtained count
+ s.GetBlock(progressCt).SetValue((uint)1); // none obtained progress value
}
}
}