mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-27 06:20:25 +00:00
Separate scblock ctor's
No longer need to set byte[] twice Add value-setter checks for bad mutations (size change, bool1<->bool2 only)
This commit is contained in:
parent
8c970ec991
commit
066aedfc21
7 changed files with 76 additions and 40 deletions
|
@ -25,7 +25,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
try { return GetBlock(key); }
|
try { return GetBlock(key); }
|
||||||
#pragma warning disable CA1031 // Do not catch general exception types
|
#pragma warning disable CA1031 // Do not catch general exception types
|
||||||
catch (KeyNotFoundException) { return new SCBlock(0); }
|
catch (KeyNotFoundException) { return new SCBlock(0, SCTypeCode.None); }
|
||||||
#pragma warning restore CA1031 // Do not catch general exception types
|
#pragma warning restore CA1031 // Do not catch general exception types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,19 +17,60 @@ namespace PKHeX.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// What kind of block is it?
|
/// What kind of block is it?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SCTypeCode Type { get; set; }
|
public SCTypeCode Type { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For <see cref="SCTypeCode.Array"/>: What kind of array is it?
|
/// For <see cref="SCTypeCode.Array"/>: What kind of array is it?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SCTypeCode SubType { get; private set; }
|
public readonly SCTypeCode SubType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decrypted data for this block.
|
/// Decrypted data for this block.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[] Data = Array.Empty<byte>();
|
public readonly byte[] Data;
|
||||||
|
|
||||||
internal SCBlock(uint key) => Key = key;
|
/// <summary>
|
||||||
|
/// Changes the block's Boolean type. Will throw if the old / new <see cref="Type"/> is not boolean.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">New boolean type to set.</param>
|
||||||
|
/// <remarks>Will throw if the requested block state changes are incorrect.</remarks>
|
||||||
|
public void ChangeBooleanType(SCTypeCode value)
|
||||||
|
{
|
||||||
|
if (Type is not (SCTypeCode.Bool1 or SCTypeCode.Bool2) || value is not (SCTypeCode.Bool1 or SCTypeCode.Bool2))
|
||||||
|
throw new InvalidOperationException($"Cannot change {Type} to {value}.");
|
||||||
|
Type = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces the current <see cref="Data"/> with a same-sized array <see cref="value"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">New array to load (copy from).</param>
|
||||||
|
/// <remarks>Will throw if the requested block state changes are incorrect.</remarks>
|
||||||
|
public void ChangeData(ReadOnlySpan<byte> value)
|
||||||
|
{
|
||||||
|
if (value.Length != Data.Length)
|
||||||
|
throw new InvalidOperationException($"Cannot change size of {Type} block from {Data.Length} to {value.Length}.");
|
||||||
|
value.CopyTo(Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal SCBlock(uint key, SCTypeCode type) : this(key, type, Array.Empty<byte>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal SCBlock(uint key, SCTypeCode type, byte[] arr)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Type = type;
|
||||||
|
Data = arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal SCBlock(uint key, byte[] arr, SCTypeCode subType)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Type = SCTypeCode.Array;
|
||||||
|
Data = arr;
|
||||||
|
SubType = subType;
|
||||||
|
}
|
||||||
|
|
||||||
public bool HasValue() => Type > SCTypeCode.Array;
|
public bool HasValue() => Type > SCTypeCode.Array;
|
||||||
public object GetValue() => Type.GetValue(Data);
|
public object GetValue() => Type.GetValue(Data);
|
||||||
|
@ -37,9 +78,11 @@ namespace PKHeX.Core
|
||||||
|
|
||||||
public SCBlock Clone()
|
public SCBlock Clone()
|
||||||
{
|
{
|
||||||
var block = (SCBlock)MemberwiseClone();
|
if (Data.Length == 0)
|
||||||
block.Data = (byte[])Data.Clone();
|
return new SCBlock(Key, Type);
|
||||||
return block;
|
if (SubType == 0)
|
||||||
|
return new SCBlock(Key, Type, (byte[]) Data.Clone());
|
||||||
|
return new SCBlock(Key, (byte[])Data.Clone(), SubType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -77,20 +120,20 @@ namespace PKHeX.Core
|
||||||
// Create block, parse its key.
|
// Create block, parse its key.
|
||||||
var key = BitConverter.ToUInt32(data, offset);
|
var key = BitConverter.ToUInt32(data, offset);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
var block = new SCBlock(key);
|
|
||||||
var xk = new SCXorShift32(key);
|
var xk = new SCXorShift32(key);
|
||||||
|
|
||||||
// Parse the block's type
|
// Parse the block's type
|
||||||
block.Type = (SCTypeCode)(data[offset++] ^ xk.Next());
|
//var block =
|
||||||
|
var type = (SCTypeCode)(data[offset++] ^ xk.Next());
|
||||||
|
|
||||||
switch (block.Type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case SCTypeCode.Bool1:
|
case SCTypeCode.Bool1:
|
||||||
case SCTypeCode.Bool2:
|
case SCTypeCode.Bool2:
|
||||||
case SCTypeCode.Bool3:
|
case SCTypeCode.Bool3:
|
||||||
// Block types are empty, and have no extra data.
|
// Block types are empty, and have no extra data.
|
||||||
Debug.Assert(block.Type != SCTypeCode.Bool3); // invalid type, haven't seen it used yet
|
Debug.Assert(type != SCTypeCode.Bool3); // invalid type, haven't seen it used yet
|
||||||
break;
|
return new SCBlock(key, type);
|
||||||
|
|
||||||
case SCTypeCode.Object: // Cast raw bytes to Object
|
case SCTypeCode.Object: // Cast raw bytes to Object
|
||||||
{
|
{
|
||||||
|
@ -99,39 +142,35 @@ namespace PKHeX.Core
|
||||||
var arr = new byte[num_bytes];
|
var arr = new byte[num_bytes];
|
||||||
for (int i = 0; i < arr.Length; i++)
|
for (int i = 0; i < arr.Length; i++)
|
||||||
arr[i] = (byte)(data[offset++] ^ xk.Next());
|
arr[i] = (byte)(data[offset++] ^ xk.Next());
|
||||||
block.Data = arr;
|
|
||||||
break;
|
return new SCBlock(key, type, arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
case SCTypeCode.Array: // Cast raw bytes to SubType[]
|
case SCTypeCode.Array: // Cast raw bytes to SubType[]
|
||||||
{
|
{
|
||||||
var num_entries = BitConverter.ToUInt32(data, offset) ^ xk.Next32();
|
var num_entries = BitConverter.ToUInt32(data, offset) ^ xk.Next32();
|
||||||
offset += 4;
|
offset += 4;
|
||||||
block.SubType = (SCTypeCode)(data[offset++] ^ xk.Next());
|
var sub = (SCTypeCode)(data[offset++] ^ xk.Next());
|
||||||
|
|
||||||
var num_bytes = num_entries * block.SubType.GetTypeSize();
|
var num_bytes = num_entries * sub.GetTypeSize();
|
||||||
var arr = new byte[num_bytes];
|
var arr = new byte[num_bytes];
|
||||||
for (int i = 0; i < arr.Length; i++)
|
for (int i = 0; i < arr.Length; i++)
|
||||||
arr[i] = (byte)(data[offset++] ^ xk.Next());
|
arr[i] = (byte)(data[offset++] ^ xk.Next());
|
||||||
block.Data = arr;
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Debug.Assert(block.SubType > SCTypeCode.Array || Array.TrueForAll(block.Data, z => z <= 1));
|
Debug.Assert(sub > SCTypeCode.Array || Array.TrueForAll(arr, z => z <= 1));
|
||||||
#endif
|
#endif
|
||||||
break;
|
return new SCBlock(key, arr, sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
default: // Single Value Storage
|
default: // Single Value Storage
|
||||||
{
|
{
|
||||||
var num_bytes = block.Type.GetTypeSize();
|
var num_bytes = type.GetTypeSize();
|
||||||
var arr = new byte[num_bytes];
|
var arr = new byte[num_bytes];
|
||||||
for (int i = 0; i < arr.Length; i++)
|
for (int i = 0; i < arr.Length; i++)
|
||||||
arr[i] = (byte)(data[offset++] ^ xk.Next());
|
arr[i] = (byte)(data[offset++] ^ xk.Next());
|
||||||
block.Data = arr;
|
return new SCBlock(key, type, arr);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ namespace PKHeX.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = File.ReadAllBytes(f);
|
var data = File.ReadAllBytes(f);
|
||||||
data.CopyTo(block.Data, 0);
|
block.ChangeData(data);
|
||||||
}
|
}
|
||||||
#pragma warning disable CA1031 // Do not catch general exception types
|
#pragma warning disable CA1031 // Do not catch general exception types
|
||||||
catch
|
catch
|
||||||
|
|
|
@ -60,7 +60,6 @@
|
||||||
key ^= key << 13;
|
key ^= key << 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !NET5
|
#if !NET5
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Count of bits set in value
|
/// Count of bits set in value
|
||||||
|
|
|
@ -169,7 +169,8 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (value.Length != 1)
|
if (value.Length != 1)
|
||||||
return;
|
return;
|
||||||
Blocks.GetBlock(SaveBlockAccessor8SWSH.KSecretBoxUnlocked).Type = (SCTypeCode)(value[0] & 1) + 1;
|
var block = Blocks.GetBlock(SaveBlockAccessor8SWSH.KSecretBoxUnlocked);
|
||||||
|
block.ChangeBooleanType((SCTypeCode)(value[0] & 1) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace PKHeX.Core
|
||||||
for (int i = 0; i < blocks.Length; i++)
|
for (int i = 0; i < blocks.Length; i++)
|
||||||
{
|
{
|
||||||
int index = i * 2;
|
int index = i * 2;
|
||||||
blocks[i] = new SCBlock(arr[index]) { Data = new byte[(int)arr[index + 1]] };
|
blocks[i] = new SCBlock(arr[index], SCTypeCode.None, new byte[(int)arr[index + 1]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return blocks;
|
return blocks;
|
||||||
|
|
|
@ -31,16 +31,13 @@ namespace PKHeX.WinForms
|
||||||
CB_Key.InitializeBinding();
|
CB_Key.InitializeBinding();
|
||||||
CB_Key.DataSource = Metadata.GetSortedBlockKeyList().ToArray();
|
CB_Key.DataSource = Metadata.GetSortedBlockKeyList().ToArray();
|
||||||
|
|
||||||
ComboItem[] boolToggle =
|
|
||||||
{
|
|
||||||
new(nameof(SCTypeCode.Bool1), (int)SCTypeCode.Bool1),
|
|
||||||
new(nameof(SCTypeCode.Bool2), (int)SCTypeCode.Bool2),
|
|
||||||
new(nameof(SCTypeCode.Bool3), (int)SCTypeCode.Bool3),
|
|
||||||
};
|
|
||||||
CB_TypeToggle.InitializeBinding();
|
CB_TypeToggle.InitializeBinding();
|
||||||
CB_TypeToggle.DataSource = boolToggle;
|
CB_TypeToggle.DataSource = new[]
|
||||||
|
{
|
||||||
CB_TypeToggle.SelectedIndexChanged += (o, args) => CB_TypeToggle_SelectedIndexChanged(CB_TypeToggle, args);
|
new ComboItem(nameof(SCTypeCode.Bool1), (int)SCTypeCode.Bool1),
|
||||||
|
new ComboItem(nameof(SCTypeCode.Bool2), (int)SCTypeCode.Bool2),
|
||||||
|
};
|
||||||
|
CB_TypeToggle.SelectedIndexChanged += CB_TypeToggle_SelectedIndexChanged;
|
||||||
|
|
||||||
CB_Key.SelectedIndex = 0;
|
CB_Key.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
@ -109,14 +106,14 @@ namespace PKHeX.WinForms
|
||||||
PG_BlockView.Visible = false;
|
PG_BlockView.Visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CB_TypeToggle_SelectedIndexChanged(object sender, EventArgs e)
|
private void CB_TypeToggle_SelectedIndexChanged(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var block = CurrentBlock;
|
var block = CurrentBlock;
|
||||||
var cType = block.Type;
|
var cType = block.Type;
|
||||||
var cValue = (SCTypeCode)WinFormsUtil.GetIndex(CB_TypeToggle);
|
var cValue = (SCTypeCode)WinFormsUtil.GetIndex(CB_TypeToggle);
|
||||||
if (cType == cValue)
|
if (cType == cValue)
|
||||||
return;
|
return;
|
||||||
block.Type = cValue;
|
block.ChangeBooleanType(cValue);
|
||||||
UpdateBlockSummaryControls();
|
UpdateBlockSummaryControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue