Minor clean

StringBuilder.Append has some fancy interpolation handling in the latest NET8 so it's more clean than multiple append calls.
This commit is contained in:
Kurt 2024-06-15 00:57:44 -05:00
parent 0ffb256052
commit f6bcc8a216
29 changed files with 216 additions and 221 deletions

View file

@ -1,6 +1,5 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Text;
namespace PKHeX.Core; namespace PKHeX.Core;
@ -55,10 +54,10 @@ public static class QRMessageUtil
/// <returns>QR Message</returns> /// <returns>QR Message</returns>
public static string GetMessage(ReadOnlySpan<byte> payload) public static string GetMessage(ReadOnlySpan<byte> payload)
{ {
var sb = new StringBuilder(payload.Length); Span<char> result = stackalloc char[payload.Length];
foreach (var b in payload) for (int i = 0; i < payload.Length; i++)
sb.Append((char)b); result[i] = (char)payload[i];
return sb.ToString(); return new string(result);
} }
/// <summary> /// <summary>

View file

@ -25,7 +25,7 @@ public readonly record struct MoveLearnInfo(LearnMethod Method, LearnEnvironment
sb.Append(Environment).Append('-'); sb.Append(Environment).Append('-');
sb.Append(localizedMethod); sb.Append(localizedMethod);
if (Method is LevelUp) if (Method is LevelUp)
sb.Append(" @ lv").Append(Argument); sb.Append($" @ lv{Argument}");
} }
private string GetLocalizedMethod() => Method switch private string GetLocalizedMethod() => Method switch

View file

@ -52,10 +52,9 @@ public readonly record struct NPCLock
sb.Append(" (Shadow)"); sb.Append(" (Shadow)");
if (Seen) if (Seen)
sb.Append(" [Seen]"); sb.Append(" [Seen]");
sb.Append(" - "); sb.Append($" - Nature: {(Nature)Nature}");
sb.Append("Nature: ").Append((Nature)Nature);
if (Gender != 2) if (Gender != 2)
sb.Append(", ").Append("Gender: ").Append(Gender); sb.Append($", Gender: {Gender}");
return sb.ToString(); return sb.ToString();
} }
#endif #endif

View file

@ -124,10 +124,6 @@ public static class GenerateMethodK
public static uint GetPIDRegular(uint a, uint b) => b << 16 | a; public static uint GetPIDRegular(uint a, uint b) => b << 16 | a;
private static void SetPIDIVSequential(PK4 pk, uint pid, uint rand)
{
}
private static (uint iv1, uint iv2) GetCombinedIVs(EncounterCriteria criteria) private static (uint iv1, uint iv2) GetCombinedIVs(EncounterCriteria criteria)
{ {
uint iv1 = (uint)criteria.IV_HP | (uint)criteria.IV_ATK << 5 | (uint)criteria.IV_DEF << 10; uint iv1 = (uint)criteria.IV_HP | (uint)criteria.IV_ATK << 5 | (uint)criteria.IV_DEF << 10;

View file

@ -352,4 +352,3 @@ public enum GiftSubType4 : byte
Accessory = 2, Accessory = 2,
Backdrop = 3, Backdrop = 3,
} }

View file

@ -705,7 +705,7 @@ public sealed class WB8(byte[] Data) : DataMysteryGift(Data),
return IsMatchLocationExact(pk) || IsMatchLocationRemapped(pk); return IsMatchLocationExact(pk) || IsMatchLocationRemapped(pk);
} }
private bool IsMatchLocationExact(PKM pk) => pk.MetLocation == this.Location; private bool IsMatchLocationExact(PKM pk) => pk.MetLocation == Location;
private bool IsMatchLocationRemapped(PKM pk) private bool IsMatchLocationRemapped(PKM pk)
{ {
@ -713,7 +713,7 @@ public sealed class WB8(byte[] Data) : DataMysteryGift(Data),
var version = pk.Version; var version = pk.Version;
if (pk.Context == EntityContext.Gen8) if (pk.Context == EntityContext.Gen8)
return LocationsHOME.IsValidMetBDSP(met, version); return LocationsHOME.IsValidMetBDSP(met, version);
return LocationsHOME.GetMetSWSH(this.Location, version) == met; return LocationsHOME.GetMetSWSH(Location, version) == met;
} }
protected override bool IsMatchDeferred(PKM pk) => false; protected override bool IsMatchDeferred(PKM pk) => false;

View file

@ -191,13 +191,13 @@ public static class StringFont8b
'\uFB30', '\uFB31', '\uFB32', '\uFB33', '\uFB34', '\uFB35', '\uFB36', '\uFB38', '\uFB39', '\uFB3A', '\uFB3B', '\uFB3C', '\uFB3E', '\uFB30', '\uFB31', '\uFB32', '\uFB33', '\uFB34', '\uFB35', '\uFB36', '\uFB38', '\uFB39', '\uFB3A', '\uFB3B', '\uFB3C', '\uFB3E',
'\uFB40', '\uFB41', '\uFB43', '\uFB44', '\uFB46', '\uFB47', '\uFB48', '\uFB49', '\uFB4A', '\uFB4B', '\uFB4C', '\uFB4D', '\uFB4E', '\uFB4F', '\uFB40', '\uFB41', '\uFB43', '\uFB44', '\uFB46', '\uFB47', '\uFB48', '\uFB49', '\uFB4A', '\uFB4B', '\uFB4C', '\uFB4D', '\uFB4E', '\uFB4F',
'\uFE20', '\uFE21', '\uFE22', '\uFE23', '\uFE20', '\uFE21', '\uFE22', '\uFE23',
'\uFFFC' '\uFFFC',
]; ];
public static ReadOnlySpan<char> DefinedCHSExt => [ public static ReadOnlySpan<char> DefinedCHSExt => [
'\u0020', '\u002D', '\u003F', '\u0067', '\u00AA', '\u00B7', '\u00E9', '\u0020', '\u002D', '\u003F', '\u0067', '\u00AA', '\u00B7', '\u00E9',
'\u2013', '\u2018', '\u2019', '\u201C', '\u201D', '\u201E', '\u2026', '\u20BD', '\u21D2', '\u21D4', '\u2200', '\u2282', '\u2283', '\u2013', '\u2018', '\u2019', '\u201C', '\u201D', '\u201E', '\u2026', '\u20BD', '\u21D2', '\u21D4', '\u2200', '\u2282', '\u2283',
'\u25A0', '\u25BC', '\u25BD', '\u25CF', '\u2605', '\u2661', '\u2665', '\u266A', '\u266D', '\u25A0', '\u25BC', '\u25BD', '\u25CF', '\u2605', '\u2661', '\u2665', '\u266A', '\u266D',
'\u300A', '\u300B', '\u300C', '\u300D', '\u300E', '\u300F', '\u3010', '\u3011', '\u30FB', '\uFF08', '\uFF09', '\uFF65' '\u300A', '\u300B', '\u300C', '\u300D', '\u300E', '\u300F', '\u3010', '\u3011', '\u30FB', '\uFF08', '\uFF09', '\uFF65',
]; ];
} }

View file

@ -105,9 +105,8 @@ public static class TrainerInfoExtensions
if (tr.Version != pk.Version) if (tr.Version != pk.Version)
{ {
// PK9 does not store version for Picnic eggs. if (!IsVersionlessState(pk))
if (pk is PK9 { Version: 0 }) { } return false;
else { return false; }
} }
Span<char> ot = stackalloc char[pk.MaxStringLengthTrainer]; Span<char> ot = stackalloc char[pk.MaxStringLengthTrainer];
@ -119,6 +118,14 @@ public static class TrainerInfoExtensions
return true; return true;
} }
private static bool IsVersionlessState(PKM pk)
{
// PK9 does not store version for Picnic eggs.
if (pk is PK9 { Version: 0 }) // IsEgg is already true for all calls
return true;
return false;
}
private static bool IsMatchVersion(ITrainerInfo tr, PKM pk) private static bool IsMatchVersion(ITrainerInfo tr, PKM pk)
{ {
if (tr.Version == pk.Version) if (tr.Version == pk.Version)

View file

@ -119,15 +119,15 @@ public static class SCBlockUtil
public static string GetBlockSummary(SCBlock b) public static string GetBlockSummary(SCBlock b)
{ {
var sb = new StringBuilder(64); var sb = new StringBuilder(64);
sb.Append("Key: ").AppendFormat("{0:X8}", b.Key).AppendLine(); sb.AppendLine($"Key: {b.Key:X8}");
sb.Append("Type: ").Append(b.Type).AppendLine(); sb.AppendLine($"Type: {b.Type}");
if (b.Data.Length != 0) if (b.Data.Length != 0)
sb.Append("Length: ").AppendFormat("{0:X8}", b.Data.Length).AppendLine(); sb.AppendLine($"Length: {b.Data.Length:X8}");
if (b.SubType != 0) if (b.SubType != 0)
sb.Append("SubType: ").Append(b.SubType).AppendLine(); sb.AppendLine($"SubType: {b.SubType}");
else if (b.HasValue()) else if (b.HasValue())
sb.Append("Value: ").Append(b.GetValue()).AppendLine(); sb.AppendLine($"Value: {b.GetValue()}");
return sb.ToString(); return sb.ToString();
} }

View file

@ -243,7 +243,6 @@ public abstract class SAV4 : SaveFile, IEventFlag37, IDaycareStorage, IDaycareRa
protected int OFS_Record = int.MinValue; protected int OFS_Record = int.MinValue;
public Record4 Records => new(this, Data.AsMemory(OFS_Record, Record4.GetSize(this))); public Record4 Records => new(this, Data.AsMemory(OFS_Record, Record4.GetSize(this)));
// Storage // Storage
public override int PartyCount public override int PartyCount
{ {

View file

@ -16,7 +16,7 @@ public sealed class SAV5B2W2 : SAV5, ISaveBlock5B2W2
public SaveBlockAccessor5B2W2 Blocks { get; } public SaveBlockAccessor5B2W2 Blocks { get; }
protected override SAV5B2W2 CloneInternal() => new((byte[]) Data.Clone()); protected override SAV5B2W2 CloneInternal() => new((byte[]) Data.Clone());
public override int MaxItemID => Legal.MaxItemID_5_B2W2; public override int MaxItemID => Legal.MaxItemID_5_B2W2;
public override IReadOnlyList<BlockInfo> AllBlocks => Blocks.BlockInfo; public override IReadOnlyList<BlockInfo> AllBlocks => Blocks.BlockInfo;
public override MyItem Items => Blocks.Items; public override MyItem Items => Blocks.Items;
public override Zukan5 Zukan => Blocks.Zukan; public override Zukan5 Zukan => Blocks.Zukan;

View file

@ -136,7 +136,7 @@ public enum DecorationCategory3 : byte
Mat, Mat,
Poster, Poster,
Doll, Doll,
Cushion Cushion,
} }
public static class DecorationInfo public static class DecorationInfo

View file

@ -45,7 +45,7 @@ public sealed class SecretBase3PKM : ISpeciesForm
{ {
sb.Append($"{Species:000} - {g.Species[Species]}"); sb.Append($"{Species:000} - {g.Species[Species]}");
if (HeldItem != 0) if (HeldItem != 0)
sb.Append(" @ ").Append(g.Item[HeldItem]); sb.Append($" @ {g.Item[HeldItem]}");
sb.AppendLine(); sb.AppendLine();
var moveNames = g.Move; var moveNames = g.Move;

View file

@ -17,9 +17,9 @@ public sealed class Record4(SAV4 SAV, Memory<byte> raw) : SaveBlock<SAV4>(SAV, r
{ {
public static int GetSize(SAV4 SAV) => SAV switch public static int GetSize(SAV4 SAV) => SAV switch
{ {
SAV4DP => Record32DP * sizeof(uint) + Record16 * sizeof(ushort), SAV4DP => (Record32DP * sizeof(uint)) +(Record16 * sizeof(ushort)),
SAV4Pt => Record32Pt * sizeof(uint) + Record16 * sizeof(ushort) + 3 * sizeof(ushort), SAV4Pt => (Record32Pt * sizeof(uint)) +(Record16 * sizeof(ushort)) + (3 * sizeof(ushort)),
SAV4HGSS => Record32HGSS * sizeof(uint) + Record16 * sizeof(ushort) + 3 * sizeof(ushort), SAV4HGSS => (Record32HGSS * sizeof(uint)) +(Record16 * sizeof(ushort)) + (3 * sizeof(ushort)),
_ => throw new ArgumentOutOfRangeException(nameof(SAV)), _ => throw new ArgumentOutOfRangeException(nameof(SAV)),
}; };
@ -70,7 +70,7 @@ public sealed class Record4(SAV4 SAV, Memory<byte> raw) : SaveBlock<SAV4>(SAV, r
/// </remarks> /// </remarks>
public uint CryptoSeed public uint CryptoSeed
{ {
get => (SAV is SAV4DP) ? (ushort)0 : ReadUInt32LittleEndian(Data[^4..]); get => (SAV is SAV4DP) ? 0 : ReadUInt32LittleEndian(Data[^4..]);
set { if (SAV is not SAV4DP) WriteUInt32LittleEndian(Data[^4..], value); } set { if (SAV is not SAV4DP) WriteUInt32LittleEndian(Data[^4..], value); }
} }
@ -81,7 +81,7 @@ public sealed class Record4(SAV4 SAV, Memory<byte> raw) : SaveBlock<SAV4>(SAV, r
{ {
if (SAV is SAV4DP || IsDecrypted == state) // DP does not encrypt records if (SAV is SAV4DP || IsDecrypted == state) // DP does not encrypt records
return; return;
if (IsDecrypted && state == false) if (IsDecrypted && !state)
RefreshChecksum(); // refresh only on encrypt RefreshChecksum(); // refresh only on encrypt
PokeCrypto.CryptArray(CryptoData, CryptoSeed); PokeCrypto.CryptArray(CryptoData, CryptoSeed);
IsDecrypted = state; IsDecrypted = state;
@ -175,14 +175,14 @@ public sealed class Record4(SAV4 SAV, Memory<byte> raw) : SaveBlock<SAV4>(SAV, r
public uint GetRecord32(int index) public uint GetRecord32(int index)
{ {
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, (uint)Record32); ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)index, (uint)Record32);
EnsureDecrypted(); EnsureDecrypted();
return ReadUInt32LittleEndian(Record32Data[(index * 4)..]); return ReadUInt32LittleEndian(Record32Data[(index * 4)..]);
} }
public void SetRecord32(int index, uint value) public void SetRecord32(int index, uint value)
{ {
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, (uint)Record32); ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)index, (uint)Record32);
EnsureDecrypted(); EnsureDecrypted();
WriteUInt32LittleEndian(Record32Data[(index * 4)..], Math.Min(GetMax32(index), value)); WriteUInt32LittleEndian(Record32Data[(index * 4)..], Math.Min(GetMax32(index), value));
} }

View file

@ -221,5 +221,5 @@ public enum MaxRaidOrigin: uint
{ {
Galar, Galar,
IsleOfArmor, IsleOfArmor,
CrownTundra CrownTundra,
} }

View file

@ -156,5 +156,5 @@ public enum TeraRaidOrigin : uint
{ {
Paldea, Paldea,
Kitakami, Kitakami,
BlueberryAcademy BlueberryAcademy,
} }

View file

@ -31,6 +31,7 @@ public interface IGeonet
/// </summary> /// </summary>
/// <param name="country">Country index</param> /// <param name="country">Country index</param>
/// <param name="subregion">Subregion index</param> /// <param name="subregion">Subregion index</param>
/// <param name="point">Point status</param>
void SetCountrySubregion(byte country, byte subregion, GeonetPoint point); void SetCountrySubregion(byte country, byte subregion, GeonetPoint point);
/// <summary> /// <summary>

View file

@ -60,7 +60,7 @@ public static class DateUtil
value %= SecondsPerDay; value %= SecondsPerDay;
sb.Append(new TimeOnly(ticks: value * TimeSpan.TicksPerSecond).ToString("HH:mm:ss")); sb.Append(new TimeOnly(ticks: value * TimeSpan.TicksPerSecond).ToString("HH:mm:ss"));
if (secondsBias >= 0) if (secondsBias >= 0)
sb.Append(Environment.NewLine).Append("Date: ").Append(Epoch2000.AddSeconds(value + secondsBias)); sb.Append(Environment.NewLine).Append($"Date: {Epoch2000.AddSeconds(value + secondsBias)}");
return sb.ToString(); return sb.ToString();
} }

View file

@ -210,11 +210,11 @@ public static class FileUtil
/// <param name="data">Binary data</param> /// <param name="data">Binary data</param>
/// <param name="pk">Output result</param> /// <param name="pk">Output result</param>
/// <param name="ext">Format hint</param> /// <param name="ext">Format hint</param>
/// <param name="sav">Reference savefile used for PC Binary compatibility checks.</param> /// <param name="sav">Reference save file used for PC Binary compatibility checks.</param>
/// <returns>True if file object reference is valid, false if none found.</returns> /// <returns>True if file object reference is valid, false if none found.</returns>
public static bool TryGetPKM(byte[] data, [NotNullWhen(true)] out PKM? pk, ReadOnlySpan<char> ext, ITrainerInfo? sav = null) public static bool TryGetPKM(byte[] data, [NotNullWhen(true)] out PKM? pk, ReadOnlySpan<char> ext, ITrainerInfo? sav = null)
{ {
if (ext == ".pgt") // size collision with pk6 if (ext.EndsWith("pgt")) // size collision with pk6
{ {
pk = null; pk = null;
return false; return false;

View file

@ -1,12 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using PKHeX.Core; using PKHeX.Core;
using static System.Buffers.Binary.BinaryPrimitives; using static System.Buffers.Binary.BinaryPrimitives;
using static PKHeX.Core.DecorationCategory3;
namespace PKHeX.WinForms; namespace PKHeX.WinForms;
@ -118,7 +116,7 @@ public partial class SAV_Misc3 : Form
TB_B1.Text = Math.Min((ushort)9999, j.JoyfulBerriesInRow).ToString(); TB_B1.Text = Math.Min((ushort)9999, j.JoyfulBerriesInRow).ToString();
TB_B2.Text = Math.Min(99990, j.JoyfulBerriesScore).ToString(); TB_B2.Text = Math.Min(99990, j.JoyfulBerriesScore).ToString();
TB_B3.Text = Math.Min((ushort)9999, j.JoyfulBerries5InRow).ToString(); TB_B3.Text = Math.Min((ushort)9999, j.JoyfulBerries5InRow).ToString();
TB_BerryPowder.Text = Math.Min((uint)99999, j.BerryPowder).ToString(); TB_BerryPowder.Text = Math.Min(99999u, j.BerryPowder).ToString();
} }
private void SaveJoyful(IGen3Joyful j) private void SaveJoyful(IGen3Joyful j)

View file

@ -756,7 +756,7 @@ public partial class SAV_Misc4 : Form
DGV_Seals.Columns.Add(dgvSlot); DGV_Seals.Columns.Add(dgvSlot);
DGV_Seals.Columns.Add(dgvCount); DGV_Seals.Columns.Add(dgvCount);
var count = (int)Seal4.MAX; const int count = (int)Seal4.MAX;
DGV_Seals.Rows.Add(count); DGV_Seals.Rows.Add(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
DGV_Seals.Rows[i].Cells[0].Value = seals[i]; DGV_Seals.Rows[i].Cells[0].Value = seals[i];
@ -825,7 +825,7 @@ public partial class SAV_Misc4 : Form
DGV_Accessories.Columns.Add(dgvSlot); DGV_Accessories.Columns.Add(dgvSlot);
DGV_Accessories.Columns.Add(dgvCount); DGV_Accessories.Columns.Add(dgvCount);
var count = AccessoryInfo.Count; const int count = AccessoryInfo.Count;
DGV_Accessories.Rows.Add(count); DGV_Accessories.Rows.Add(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
DGV_Accessories.Rows[i].Cells[0].Value = accessories[i]; DGV_Accessories.Rows[i].Cells[0].Value = accessories[i];

View file

@ -21,7 +21,7 @@ public partial class SAV_Raid8 : Form
MaxRaidOrigin.Galar => SAV.RaidGalar, MaxRaidOrigin.Galar => SAV.RaidGalar,
MaxRaidOrigin.IsleOfArmor => SAV.RaidArmor, MaxRaidOrigin.IsleOfArmor => SAV.RaidArmor,
MaxRaidOrigin.CrownTundra => SAV.RaidCrown, MaxRaidOrigin.CrownTundra => SAV.RaidCrown,
_ => throw new ArgumentOutOfRangeException($"Raid Origin {raidOrigin} is not valid for Sword and Shield") _ => throw new ArgumentOutOfRangeException($"Raid Origin {raidOrigin} is not valid for Sword and Shield"),
}; };
CB_Den.Items.AddRange(Enumerable.Range(1, Raids.CountUsed).Select(z => (object)$"Den {z:000}").ToArray()); CB_Den.Items.AddRange(Enumerable.Range(1, Raids.CountUsed).Select(z => (object)$"Den {z:000}").ToArray());
CB_Den.SelectedIndex = 0; CB_Den.SelectedIndex = 0;

View file

@ -156,7 +156,6 @@ public partial class SAV_PokedexSVKitakami : Form
if (forms[0].Length == 0) if (forms[0].Length == 0)
forms[0] = GameInfo.Strings.Types[0]; forms[0] = GameInfo.Strings.Types[0];
this.SuspendLayout();
// Clear all CheckedListBoxes // Clear all CheckedListBoxes
var seen = CLB_FormSeen.Items; var seen = CLB_FormSeen.Items;
var obtained = CLB_FormObtained.Items; var obtained = CLB_FormObtained.Items;

View file

@ -22,7 +22,7 @@ public partial class SAV_Raid9 : Form
TeraRaidOrigin.Paldea => SAV.RaidPaldea, TeraRaidOrigin.Paldea => SAV.RaidPaldea,
TeraRaidOrigin.Kitakami => SAV.RaidKitakami, TeraRaidOrigin.Kitakami => SAV.RaidKitakami,
TeraRaidOrigin.BlueberryAcademy => SAV.RaidBlueberry, TeraRaidOrigin.BlueberryAcademy => SAV.RaidBlueberry,
_ => throw new ArgumentOutOfRangeException($"Raid Origin {raidOrigin} is not valid for Scarlet and Violet") _ => throw new ArgumentOutOfRangeException($"Raid Origin {raidOrigin} is not valid for Scarlet and Violet"),
}; };
CB_Raid.Items.AddRange(Enumerable.Range(1, Raids.CountUsed).Select(z => (object)$"Raid {z:000}").ToArray()); CB_Raid.Items.AddRange(Enumerable.Range(1, Raids.CountUsed).Select(z => (object)$"Raid {z:000}").ToArray());
CB_Raid.SelectedIndex = 0; CB_Raid.SelectedIndex = 0;

View file

@ -7,182 +7,181 @@ using System.Windows.Forms;
using PKHeX.Core; using PKHeX.Core;
using PKHeX.WinForms.Controls; using PKHeX.WinForms.Controls;
namespace PKHeX.WinForms namespace PKHeX.WinForms;
public static class DevUtil
{ {
public static class DevUtil public static void AddControl(ToolStripDropDownItem t)
{ {
public static void AddControl(ToolStripDropDownItem t) t.DropDownItems.Add(GetTranslationUpdater());
}
private static readonly string[] Languages = ["ja", "fr", "it", "de", "es", "ko", "zh", "zh2"];
private static string DefaultLanguage => Main.CurrentLanguage;
public static bool IsUpdatingTranslations { get; private set; }
/// <summary>
/// Call this to update all translatable resources (Program Messages, Legality Text, Program GUI)
/// </summary>
private static void UpdateAll()
{
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Update translation files with current values?"))
return;
IsUpdatingTranslations = true;
DumpStringsLegality();
DumpStringsMessage();
UpdateTranslations();
IsUpdatingTranslations = false;
}
private static ToolStripMenuItem GetTranslationUpdater()
{
var ti = new ToolStripMenuItem
{ {
t.DropDownItems.Add(GetTranslationUpdater()); ShortcutKeys = Keys.Control | Keys.Alt | Keys.D,
Visible = false,
};
ti.Click += (_, _) => UpdateAll();
return ti;
}
private static void UpdateTranslations()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var types = assembly.GetTypes();
// Trigger a translation then dump all.
foreach (var lang in Languages) // get all languages ready to go
_ = WinFormsTranslator.GetDictionary(lang);
WinFormsTranslator.SetUpdateMode();
WinFormsTranslator.LoadSettings<PKHeXSettings>(DefaultLanguage);
WinFormsTranslator.LoadEnums(EnumTypesToTranslate, DefaultLanguage);
WinFormsTranslator.LoadAllForms(types, LoadBanlist); // populate with every possible control
WinFormsTranslator.TranslateControls(GetExtraControls(), DefaultLanguage);
var dir = GetResourcePath("PKHeX.WinForms", "Resources", "text");
WinFormsTranslator.DumpAll(DefaultLanguage, Banlist, dir); // dump current to file
WinFormsTranslator.SetUpdateMode(false);
// Move translated files from the debug exe loc to their project location
var files = Directory.GetFiles(Application.StartupPath);
foreach (var f in files)
{
var fn = Path.GetFileName(f);
if (!fn.EndsWith(".txt"))
continue;
if (!fn.StartsWith("lang_"))
continue;
var loc = Path.Combine(dir, fn);
if (File.Exists(loc))
File.Delete(loc);
File.Move(f, loc, true);
} }
private static readonly string[] Languages = ["ja", "fr", "it", "de", "es", "ko", "zh", "zh2"]; Application.Exit();
private static string DefaultLanguage => Main.CurrentLanguage; }
public static bool IsUpdatingTranslations { get; private set; } private static readonly Type[] EnumTypesToTranslate =
[
typeof(StatusCondition),
typeof(PokeSize),
typeof(PokeSizeDetailed),
/// <summary> typeof(PassPower5),
/// Call this to update all translatable resources (Program Messages, Legality Text, Program GUI) typeof(Funfest5Mission),
/// </summary> typeof(OPower6Index),
private static void UpdateAll() typeof(OPower6FieldType),
typeof(OPower6BattleType),
typeof(PlayerBattleStyle7),
typeof(PlayerSkinColor7),
typeof(Stamp7),
typeof(FestivalPlazaFacilityColor),
];
private static IEnumerable<Control> GetExtraControls()
{
foreach (var name in SlotList.GetEnumNames().Distinct())
yield return new Label { Name = $"{nameof(Main)}.L_{name}", Text = name };
}
private static readonly string[] LoadBanlist =
[
nameof(SplashScreen),
nameof(PokePreview),
];
private static readonly string[] Banlist =
[
"Gender=", // editor gender labels
"BTN_Shinytize", // ☆
"Hidden_", // Hidden controls
"CAL_", // calendar controls now expose Text, don't care.
".Count", // enum count
$"{nameof(Main)}.L_SizeH", // height rating
$"{nameof(Main)}.L_SizeW", // weight rating
$"{nameof(Main)}.L_SizeS", // scale rating
$"{nameof(Main)}.B_Box", // << and >> arrows
$"{nameof(Main)}.L_Characteristic=", // Characterstic (dynamic)
$"{nameof(Main)}.L_Potential", // ★☆☆☆ IV judge evaluation
$"{nameof(SAV_HoneyTree)}.L_Tree0", // dynamic, don't bother
$"{nameof(SAV_Misc3)}.BTN_Symbol", // symbols should stay as their current character
$"{nameof(SAV_GameSelect)}.L_Prompt", // prompt text (dynamic)
$"{nameof(SAV_BlockDump8)}.L_BlockName", // Block name (dynamic)
$"{nameof(SAV_PokedexResearchEditorLA)}.L_", // Dynamic label
$"{nameof(SAV_OPower)}.L_", // Dynamic label
];
private static void DumpStringsMessage() => DumpStrings(typeof(MessageStrings), false, "PKHeX.Core", "Resources", "text", "program");
private static void DumpStringsLegality() => DumpStrings(typeof(LegalityCheckStrings), true, "PKHeX.Core", "Resources", "legality", "checks");
private static void DumpStrings(Type t, bool sorted, params string[] rel)
{
var dir = GetResourcePath(rel);
DumpStrings(t, sorted, DefaultLanguage, dir);
foreach (var lang in Languages)
DumpStrings(t, sorted, lang, dir);
}
private static void DumpStrings(Type t, bool sorted, string lang, string dir)
{
LocalizationUtil.SetLocalization(t, lang);
var entries = LocalizationUtil.GetLocalization(t);
IEnumerable<string> export = entries.OrderBy(GetName); // sorted lines
if (!sorted)
export = entries;
var location = GetFileLocationInText(t.Name, dir, lang);
File.WriteAllLines(location, export);
LocalizationUtil.SetLocalization(t, DefaultLanguage);
static string GetName(string line)
{ {
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Update translation files with current values?")) var index = line.IndexOf('=');
return; if (index == -1)
IsUpdatingTranslations = true; return line;
DumpStringsLegality(); return line[..index];
DumpStringsMessage();
UpdateTranslations();
IsUpdatingTranslations = false;
} }
}
private static ToolStripMenuItem GetTranslationUpdater() private static string GetFileLocationInText(string fileType, string dir, string lang)
{
var fn = $"{fileType}_{lang}.txt";
return Path.Combine(dir, fn);
}
private static string GetResourcePath(params string[] subdir)
{
// Starting from the executable path, crawl upwards until we get to the repository/sln root
const string repo = "PKHeX";
var path = Application.StartupPath;
while (true)
{ {
var ti = new ToolStripMenuItem var parent = Directory.GetParent(path) ?? throw new DirectoryNotFoundException(path);
{ path = parent.FullName;
ShortcutKeys = Keys.Control | Keys.Alt | Keys.D, if (path.EndsWith(repo))
Visible = false, return Path.Combine(path, Path.Combine(subdir));
};
ti.Click += (_, _) => UpdateAll();
return ti;
}
private static void UpdateTranslations()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var types = assembly.GetTypes();
// Trigger a translation then dump all.
foreach (var lang in Languages) // get all languages ready to go
_ = WinFormsTranslator.GetDictionary(lang);
WinFormsTranslator.SetUpdateMode();
WinFormsTranslator.LoadSettings<PKHeXSettings>(DefaultLanguage);
WinFormsTranslator.LoadEnums(EnumTypesToTranslate, DefaultLanguage);
WinFormsTranslator.LoadAllForms(types, LoadBanlist); // populate with every possible control
WinFormsTranslator.TranslateControls(GetExtraControls(), DefaultLanguage);
var dir = GetResourcePath("PKHeX.WinForms", "Resources", "text");
WinFormsTranslator.DumpAll(DefaultLanguage, Banlist, dir); // dump current to file
WinFormsTranslator.SetUpdateMode(false);
// Move translated files from the debug exe loc to their project location
var files = Directory.GetFiles(Application.StartupPath);
foreach (var f in files)
{
var fn = Path.GetFileName(f);
if (!fn.EndsWith(".txt"))
continue;
if (!fn.StartsWith("lang_"))
continue;
var loc = Path.Combine(dir, fn);
if (File.Exists(loc))
File.Delete(loc);
File.Move(f, loc, true);
}
Application.Exit();
}
private static readonly Type[] EnumTypesToTranslate =
[
typeof(StatusCondition),
typeof(PokeSize),
typeof(PokeSizeDetailed),
typeof(PassPower5),
typeof(Funfest5Mission),
typeof(OPower6Index),
typeof(OPower6FieldType),
typeof(OPower6BattleType),
typeof(PlayerBattleStyle7),
typeof(PlayerSkinColor7),
typeof(Stamp7),
typeof(FestivalPlazaFacilityColor),
];
private static IEnumerable<Control> GetExtraControls()
{
foreach (var name in SlotList.GetEnumNames().Distinct())
yield return new Label { Name = $"{nameof(Main)}.L_{name}", Text = name };
}
private static readonly string[] LoadBanlist =
[
nameof(SplashScreen),
nameof(PokePreview),
];
private static readonly string[] Banlist =
[
"Gender=", // editor gender labels
"BTN_Shinytize", // ☆
"Hidden_", // Hidden controls
"CAL_", // calendar controls now expose Text, don't care.
".Count", // enum count
$"{nameof(Main)}.L_SizeH", // height rating
$"{nameof(Main)}.L_SizeW", // weight rating
$"{nameof(Main)}.L_SizeS", // scale rating
$"{nameof(Main)}.B_Box", // << and >> arrows
$"{nameof(Main)}.L_Characteristic=", // Characterstic (dynamic)
$"{nameof(Main)}.L_Potential", // ★☆☆☆ IV judge evaluation
$"{nameof(SAV_HoneyTree)}.L_Tree0", // dynamic, don't bother
$"{nameof(SAV_Misc3)}.BTN_Symbol", // symbols should stay as their current character
$"{nameof(SAV_GameSelect)}.L_Prompt", // prompt text (dynamic)
$"{nameof(SAV_BlockDump8)}.L_BlockName", // Block name (dynamic)
$"{nameof(SAV_PokedexResearchEditorLA)}.L_", // Dynamic label
$"{nameof(SAV_OPower)}.L_", // Dynamic label
];
private static void DumpStringsMessage() => DumpStrings(typeof(MessageStrings), false, "PKHeX.Core", "Resources", "text", "program");
private static void DumpStringsLegality() => DumpStrings(typeof(LegalityCheckStrings), true, "PKHeX.Core", "Resources", "legality", "checks");
private static void DumpStrings(Type t, bool sorted, params string[] rel)
{
var dir = GetResourcePath(rel);
DumpStrings(t, sorted, DefaultLanguage, dir);
foreach (var lang in Languages)
DumpStrings(t, sorted, lang, dir);
}
private static void DumpStrings(Type t, bool sorted, string lang, string dir)
{
LocalizationUtil.SetLocalization(t, lang);
var entries = LocalizationUtil.GetLocalization(t);
IEnumerable<string> export = entries.OrderBy(GetName); // sorted lines
if (!sorted)
export = entries;
var location = GetFileLocationInText(t.Name, dir, lang);
File.WriteAllLines(location, export);
LocalizationUtil.SetLocalization(t, DefaultLanguage);
static string GetName(string line)
{
var index = line.IndexOf('=');
if (index == -1)
return line;
return line[..index];
}
}
private static string GetFileLocationInText(string fileType, string dir, string lang)
{
var fn = $"{fileType}_{lang}.txt";
return Path.Combine(dir, fn);
}
private static string GetResourcePath(params string[] subdir)
{
// Starting from the executable path, crawl upwards until we get to the repository/sln root
const string repo = "PKHeX";
var path = Application.StartupPath;
while (true)
{
var parent = Directory.GetParent(path) ?? throw new DirectoryNotFoundException(path);
path = parent.FullName;
if (path.EndsWith(repo))
return Path.Combine(path, Path.Combine(subdir));
}
} }
} }
} }

View file

@ -262,7 +262,7 @@ public static class WinFormsUtil
{ {
var sb = new StringBuilder(128); var sb = new StringBuilder(128);
foreach (var type in extensions) foreach (var type in extensions)
sb.Append("*.").Append(type).Append(';'); sb.Append($"*.{type};");
sb.Append("*.pk"); sb.Append("*.pk");
string supported = sb.ToString(); string supported = sb.ToString();

View file

@ -1,4 +1,3 @@
using System;
using FluentAssertions; using FluentAssertions;
using Xunit; using Xunit;

View file

@ -128,7 +128,7 @@ public static class PIDTests
[0xF2AC8419, 0xADA208E3, 0xDB3A0BA6, 0x5EEF1076], [0xF2AC8419, 0xADA208E3, 0xDB3A0BA6, 0x5EEF1076],
[0x9D28899D, 0xA3ECC9F0, 0x606EC6F0, 0x451FAE3C], [0x9D28899D, 0xA3ECC9F0, 0x606EC6F0, 0x451FAE3C],
}, },
Delcatty Delcatty,
]; ];
yield return yield return
[ [
@ -145,7 +145,7 @@ public static class PIDTests
[0xC7315E32, 0x76566AA1, 0xC0CE436E, 0x98C45DA8, 0x9D1BDC4A], [0xC7315E32, 0x76566AA1, 0xC0CE436E, 0x98C45DA8, 0x9D1BDC4A],
[0xB687F0AF, 0xC01DB6C6, 0xAD6DEC75, 0xDB041314, 0x0D949325], [0xB687F0AF, 0xC01DB6C6, 0xAD6DEC75, 0xDB041314, 0x0D949325],
}, },
Butterfree Butterfree,
]; ];
} }

View file

@ -54,9 +54,9 @@ public class StringTests
private static string Hex(ReadOnlySpan<byte> outdata) private static string Hex(ReadOnlySpan<byte> outdata)
{ {
var sb = new System.Text.StringBuilder(outdata.Length); var sb = new System.Text.StringBuilder(outdata.Length*3);
foreach (var b in outdata) foreach (var b in outdata)
sb.Append(b.ToString("X2")).Append(' '); sb.Append($"{b:X2} ");
return sb.ToString(); return sb.ToString();
} }