2023-01-22 04:02:33 +00:00
|
|
|
using System;
|
2024-06-05 05:50:18 +00:00
|
|
|
using System.Collections.Concurrent;
|
2023-01-22 04:02:33 +00:00
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2024-06-05 05:50:18 +00:00
|
|
|
using System.Resources;
|
2020-12-22 03:13:18 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
namespace PKHeX.Core;
|
|
|
|
|
|
|
|
public static partial class Util
|
2020-12-22 03:13:18 +00:00
|
|
|
{
|
2024-06-05 05:50:18 +00:00
|
|
|
public static EmbeddedResourceCache ResourceCache { get; } = new(typeof(Util).Assembly);
|
2021-05-15 18:56:06 +00:00
|
|
|
|
2024-06-05 05:50:18 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Expose for plugin use/reuse so that plugins can cache their own strings without needing to manage their own cache.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// Assume the plugins won't wipe/modify, but if they do, that's on them.
|
|
|
|
/// Might enable some tweaks to work like changing species names.
|
|
|
|
/// </remarks>
|
|
|
|
public static ConcurrentDictionary<string, string[]> CachedStrings { get; } = [];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
#region String Lists
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a list of all Pokémon species names.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="language">Language of the Pokémon species names to select (e.g. "en", "fr", "jp", etc.)</param>
|
|
|
|
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon species name.</returns>
|
|
|
|
public static string[] GetSpeciesList(string language) => GetStringList("species", language);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a list of all move names.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="language">Language of the move names to select (e.g. "en", "fr", "jp", etc.)</param>
|
|
|
|
/// <returns>An array of strings whose indexes correspond to the IDs of each move name.</returns>
|
|
|
|
public static string[] GetMovesList(string language) => GetStringList("moves", language);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a list of all Pokémon ability names.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="language">Language of the Pokémon ability names to select (e.g. "en", "fr", "jp", etc.)</param>
|
|
|
|
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon ability name.</returns>
|
|
|
|
public static string[] GetAbilitiesList(string language) => GetStringList("abilities", language);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a list of all Pokémon nature names.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="language">Language of the Pokémon nature names to select (e.g. "en", "fr", "jp", etc.)</param>
|
|
|
|
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon nature name.</returns>
|
|
|
|
public static string[] GetNaturesList(string language) => GetStringList("natures", language);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a list of all Pokémon form names.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="language">Language of the Pokémon form names to select (e.g. "en", "fr", "jp", etc.)</param>
|
|
|
|
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon form name.</returns>
|
|
|
|
public static string[] GetFormsList(string language) => GetStringList("forms", language);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a list of all Pokémon type names.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="language">Language of the Pokémon type names to select (e.g. "en", "fr", "jp", etc.)</param>
|
|
|
|
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon type name.</returns>
|
|
|
|
public static string[] GetTypesList(string language) => GetStringList("types", language);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a list of all Pokémon characteristic.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="language">Language of the Pokémon characteristic to select (e.g. "en", "fr", "jp", etc.)</param>
|
|
|
|
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon characteristic.</returns>
|
|
|
|
public static string[] GetCharacteristicsList(string language) => GetStringList("character", language);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a list of all items.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="language">Language of the items to select (e.g. "en", "fr", "jp", etc.)</param>
|
|
|
|
/// <returns>An array of strings whose indexes correspond to the IDs of each item.</returns>
|
|
|
|
public static string[] GetItemsList(string language) => GetStringList("items", language);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves the localization index list for all requested strings for the <see cref="fileName"/> through Spanish.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="fileName">Base file name</param>
|
|
|
|
/// <remarks>Ignores Korean Language.</remarks>
|
2024-05-27 15:33:25 +00:00
|
|
|
public static string[][] GetLanguageStrings7([ConstantExpected] string fileName) =>
|
2023-12-04 04:13:20 +00:00
|
|
|
[
|
|
|
|
[], // 0 - None
|
2022-06-18 18:04:24 +00:00
|
|
|
GetStringList(fileName, "ja"), // 1
|
|
|
|
GetStringList(fileName, "en"), // 2
|
|
|
|
GetStringList(fileName, "fr"), // 3
|
|
|
|
GetStringList(fileName, "it"), // 4
|
|
|
|
GetStringList(fileName, "de"), // 5
|
2023-12-04 04:13:20 +00:00
|
|
|
[], // 6 - None
|
2022-06-18 18:04:24 +00:00
|
|
|
GetStringList(fileName, "es"), // 7
|
2023-12-04 04:13:20 +00:00
|
|
|
];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves the localization index list for all requested strings for the <see cref="fileName"/> through Korean.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="fileName">Base file name</param>
|
2024-05-27 15:33:25 +00:00
|
|
|
public static string[][] GetLanguageStrings8([ConstantExpected] string fileName) =>
|
2023-12-04 04:13:20 +00:00
|
|
|
[
|
|
|
|
[], // 0 - None
|
2022-06-18 18:04:24 +00:00
|
|
|
GetStringList(fileName, "ja"), // 1
|
|
|
|
GetStringList(fileName, "en"), // 2
|
|
|
|
GetStringList(fileName, "fr"), // 3
|
|
|
|
GetStringList(fileName, "it"), // 4
|
|
|
|
GetStringList(fileName, "de"), // 5
|
2023-12-04 04:13:20 +00:00
|
|
|
[], // 6 - None
|
2022-06-18 18:04:24 +00:00
|
|
|
GetStringList(fileName, "es"), // 7
|
|
|
|
GetStringList(fileName, "ko"), // 8
|
2023-12-04 04:13:20 +00:00
|
|
|
];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves the localization index list for all requested strings for the <see cref="fileName"/> through Chinese.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="fileName">Base file name</param>
|
2024-09-04 23:51:35 +00:00
|
|
|
/// <param name="zh">Language code to use for both Chinese localizations.</param>
|
|
|
|
public static string[][] GetLanguageStrings10([ConstantExpected] string fileName, string? zh = null) =>
|
2023-12-04 04:13:20 +00:00
|
|
|
[
|
|
|
|
[], // 0 - None
|
2022-06-18 18:04:24 +00:00
|
|
|
GetStringList(fileName, "ja"), // 1
|
|
|
|
GetStringList(fileName, "en"), // 2
|
|
|
|
GetStringList(fileName, "fr"), // 3
|
|
|
|
GetStringList(fileName, "it"), // 4
|
|
|
|
GetStringList(fileName, "de"), // 5
|
2023-12-04 04:13:20 +00:00
|
|
|
[], // 6 - None
|
2022-06-18 18:04:24 +00:00
|
|
|
GetStringList(fileName, "es"), // 7
|
|
|
|
GetStringList(fileName, "ko"), // 8
|
2024-09-04 23:51:35 +00:00
|
|
|
GetStringList(fileName, zh ?? "zh-Hans"), // 9
|
|
|
|
GetStringList(fileName, zh ?? "zh-Hant"), // 10
|
2023-12-04 04:13:20 +00:00
|
|
|
];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2024-06-05 05:50:18 +00:00
|
|
|
/// <inheritdoc cref="GetStringList(string, EmbeddedResourceCache)"/>
|
2022-06-18 18:04:24 +00:00
|
|
|
public static string[] GetStringList(string fileName)
|
|
|
|
{
|
2024-06-05 05:50:18 +00:00
|
|
|
if (CachedStrings.TryGetValue(fileName, out var result))
|
2022-06-18 18:04:24 +00:00
|
|
|
return result;
|
2024-06-05 05:50:18 +00:00
|
|
|
return LoadAndCache(fileName, ResourceCache);
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2020-12-22 03:13:18 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
/// <summary>
|
2024-06-05 05:50:18 +00:00
|
|
|
/// Gets a string array from an assembly's resources.
|
2022-06-18 18:04:24 +00:00
|
|
|
/// </summary>
|
2024-06-05 05:50:18 +00:00
|
|
|
/// <remarks>Caches the result array for future fetches of the same resource.</remarks>
|
|
|
|
public static string[] GetStringList(string fileName, EmbeddedResourceCache src)
|
2022-06-18 18:04:24 +00:00
|
|
|
{
|
2024-06-05 05:50:18 +00:00
|
|
|
if (CachedStrings.TryGetValue(fileName, out var result))
|
|
|
|
return result;
|
|
|
|
return LoadAndCache(fileName, src);
|
|
|
|
}
|
2020-12-22 03:13:18 +00:00
|
|
|
|
2024-06-05 05:50:18 +00:00
|
|
|
private static string[] LoadAndCache(string fileName, EmbeddedResourceCache src)
|
|
|
|
{
|
|
|
|
if (!src.TryGetStringResource(fileName, out var txt)) // Fetch File, \n to list.
|
|
|
|
return []; // Instead of throwing an exception, return empty.
|
|
|
|
var result = FastSplit(txt); // could just string.Split but we know ours are \n or \r\n
|
|
|
|
CachedStrings.TryAdd(fileName, result);
|
|
|
|
return result;
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2020-12-22 03:13:18 +00:00
|
|
|
|
2024-05-27 15:33:25 +00:00
|
|
|
public static string[] GetStringList(string fileName, string lang2char, [ConstantExpected] string type = "text") => GetStringList(GetFullResourceName(fileName, lang2char, type));
|
2020-12-22 03:13:18 +00:00
|
|
|
|
2024-05-27 15:33:25 +00:00
|
|
|
private static string GetFullResourceName(string fileName, string lang2char, [ConstantExpected] string type) => $"{type}_{fileName}_{lang2char}";
|
2021-08-06 00:05:39 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static byte[] GetBinaryResource(string name)
|
|
|
|
{
|
2024-06-05 05:50:18 +00:00
|
|
|
if (!ResourceCache.TryGetBinaryResource(name, out var result))
|
|
|
|
throw new MissingManifestResourceException($"Resource not found: {name}");
|
|
|
|
return result;
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2021-05-15 18:56:06 +00:00
|
|
|
|
2024-06-05 05:50:18 +00:00
|
|
|
public static string GetStringResource(string name)
|
2022-06-18 18:04:24 +00:00
|
|
|
{
|
2024-06-05 05:50:18 +00:00
|
|
|
if (!ResourceCache.TryGetStringResource(name, out var result))
|
|
|
|
throw new MissingManifestResourceException($"Resource not found: {name}");
|
|
|
|
return result;
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static string[] FastSplit(ReadOnlySpan<char> s)
|
|
|
|
{
|
|
|
|
// Get Count
|
|
|
|
if (s.Length == 0)
|
2023-12-04 04:13:20 +00:00
|
|
|
return [];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
2024-05-27 15:33:25 +00:00
|
|
|
var count = 1 + s.Count('\n');
|
2022-06-18 18:04:24 +00:00
|
|
|
var result = new string[count];
|
|
|
|
|
|
|
|
var i = 0;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
var index = s.IndexOf('\n');
|
|
|
|
var length = index == -1 ? s.Length : index;
|
|
|
|
var slice = s[..length];
|
|
|
|
if (slice.Length != 0 && slice[^1] == '\r')
|
|
|
|
slice = slice[..^1];
|
|
|
|
|
|
|
|
result[i++] = slice.ToString();
|
|
|
|
if (i == count)
|
|
|
|
return result;
|
|
|
|
s = s[(index + 1)..];
|
2020-12-22 03:13:18 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2020-12-22 03:13:18 +00:00
|
|
|
}
|