Files
aibis-dream/Assets/Editor/Localization/LocalizedObjSpriteValidator.cs
T

169 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AibisDream.UI;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
namespace AibisDream.EditorTools.Localization
{
public readonly struct LocalizedObjSpriteValidationIssue
{
public LocalizedObjSpriteValidationIssue(string assetPath, string message)
{
AssetPath = assetPath;
Message = message;
}
public string AssetPath { get; }
public string Message { get; }
public override string ToString()
{
return $"{AssetPath}: {Message}";
}
}
/// <summary>
/// Validates localized Obj sprite groups without depending on Yarn references or
/// Unity Localization asset tables. A group becomes localized as soon as one
/// supported non-Chinese suffix is present.
/// </summary>
public static class LocalizedObjSpriteValidator
{
internal const string DefaultObjSpriteRoot = "Assets/RawResources/Art/Obj";
private const string MenuPath =
"Tools/AIBIS/Localization/Validate Localized Obj Sprites";
[MenuItem(MenuPath)]
public static void ValidateFromMenu()
{
IReadOnlyList<LocalizedObjSpriteValidationIssue> issues = Validate();
LogIssues(issues);
if (issues.Count == 0)
{
Debug.Log(
"[LocalizedObjSpriteValidator] Validation passed. " +
"All detected localized Obj sprite groups are complete.");
}
}
public static IReadOnlyList<LocalizedObjSpriteValidationIssue> Validate(
string rootPath = DefaultObjSpriteRoot)
{
var issues = new List<LocalizedObjSpriteValidationIssue>();
if (!Directory.Exists(rootPath))
{
issues.Add(new LocalizedObjSpriteValidationIssue(
ToAssetPath(rootPath),
"Obj sprite root does not exist."));
return issues;
}
var localizedGroups = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (string filePath in Directory.EnumerateFiles(
rootPath,
"*.png",
SearchOption.AllDirectories))
{
string fileName = Path.GetFileNameWithoutExtension(filePath);
if (!LocalizedObjSpriteNaming.TryParseLocalizedVariant(
fileName,
out string logicalName,
out _))
{
continue;
}
if (string.IsNullOrWhiteSpace(logicalName))
{
issues.Add(new LocalizedObjSpriteValidationIssue(
ToAssetPath(filePath),
"Localized variant has an empty logical name."));
continue;
}
string directory = Path.GetDirectoryName(filePath) ?? rootPath;
localizedGroups.Add(Path.Combine(directory, logicalName));
}
foreach (string groupPath in localizedGroups.OrderBy(
path => path,
StringComparer.OrdinalIgnoreCase))
{
ValidateRequiredFile(
$"{groupPath}.png",
LocalizedObjSpriteNaming.DefaultLocaleCode,
issues);
foreach (string localeCode in
LocalizedObjSpriteNaming.NonDefaultLocaleCodes)
{
ValidateRequiredFile(
$"{groupPath}-{localeCode}.png",
localeCode,
issues);
}
}
return issues;
}
internal static void LogIssues(
IReadOnlyList<LocalizedObjSpriteValidationIssue> issues)
{
foreach (LocalizedObjSpriteValidationIssue issue in issues)
Debug.LogError($"[LocalizedObjSpriteValidator] {issue}");
}
private static void ValidateRequiredFile(
string filePath,
string localeCode,
ICollection<LocalizedObjSpriteValidationIssue> issues)
{
if (File.Exists(filePath))
return;
issues.Add(new LocalizedObjSpriteValidationIssue(
ToAssetPath(filePath),
$"Missing required '{localeCode}' sprite variant."));
}
private static string ToAssetPath(string path)
{
return path.Replace('\\', '/');
}
}
public sealed class LocalizedObjSpriteBuildValidator : IPreprocessBuildWithReport
{
// Run before build preprocessors that mutate version information.
public int callbackOrder => -1000;
public void OnPreprocessBuild(BuildReport report)
{
IReadOnlyList<LocalizedObjSpriteValidationIssue> issues =
LocalizedObjSpriteValidator.Validate();
if (issues.Count == 0)
return;
LocalizedObjSpriteValidator.LogIssues(issues);
string summary = string.Join(
Environment.NewLine,
issues.Take(20).Select(issue => issue.ToString()));
if (issues.Count > 20)
{
summary += Environment.NewLine +
$"... and {issues.Count - 20} more issue(s).";
}
throw new BuildFailedException(
"Localized Obj sprite validation failed:" +
Environment.NewLine + summary);
}
}
}