fix: 垃圾测试
This commit is contained in:
@@ -1,416 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AibisDream.UI;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.EditorTools.Localization
|
||||
{
|
||||
internal readonly struct LocalizedObjSpriteDirectory
|
||||
{
|
||||
internal LocalizedObjSpriteDirectory(
|
||||
string localeCode,
|
||||
string folderName,
|
||||
string addressRoot,
|
||||
string groupName)
|
||||
{
|
||||
LocaleCode = localeCode;
|
||||
FolderName = folderName;
|
||||
AddressRoot = addressRoot;
|
||||
GroupName = groupName;
|
||||
}
|
||||
|
||||
internal string LocaleCode { get; }
|
||||
internal string FolderName { get; }
|
||||
internal string AddressRoot { get; }
|
||||
internal string GroupName { get; }
|
||||
}
|
||||
|
||||
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 locale-specific Obj folders without depending on Yarn references or
|
||||
/// Unity Localization asset tables. A logical image becomes localized as soon as
|
||||
/// it appears in any non-Chinese locale folder.
|
||||
/// </summary>
|
||||
public static class LocalizedObjSpriteValidator
|
||||
{
|
||||
internal const string DefaultArtRoot = "Assets/RawResources/Art";
|
||||
internal const string DefaultFolderName = "Obj";
|
||||
internal const string DefaultGroupName = "Shared_UI";
|
||||
|
||||
internal static readonly LocalizedObjSpriteDirectory[] LocaleDirectories =
|
||||
{
|
||||
new("en", "Obj_en", "Sprite/Obj_en", "Shared_ObjEn"),
|
||||
new("ja-JP", "Obj_ja-JP", "Sprite/Obj_ja-JP", "Shared_ObjJaJp"),
|
||||
new("ru", "Obj_ru", "Sprite/Obj_ru", "Shared_ObjRu"),
|
||||
new("es", "Obj_es", "Sprite/Obj_es", "Shared_ObjEs"),
|
||||
new("pt-BR", "Obj_pt-BR", "Sprite/Obj_pt-BR", "Shared_ObjPtBr")
|
||||
};
|
||||
|
||||
private const string ValidateMenuPath =
|
||||
"Tools/AIBIS/Localization/Validate Localized Obj Sprites";
|
||||
private const string ConfigureMenuPath =
|
||||
"Tools/AIBIS/Localization/Configure Localized Obj Addressables";
|
||||
|
||||
[MenuItem(ValidateMenuPath)]
|
||||
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 and Addressables are complete.");
|
||||
}
|
||||
}
|
||||
|
||||
public static IReadOnlyList<LocalizedObjSpriteValidationIssue> Validate(
|
||||
string artRoot = DefaultArtRoot,
|
||||
bool validateAddressables = true)
|
||||
{
|
||||
var issues = new List<LocalizedObjSpriteValidationIssue>();
|
||||
if (!Directory.Exists(artRoot))
|
||||
{
|
||||
issues.Add(new LocalizedObjSpriteValidationIssue(
|
||||
ToAssetPath(artRoot),
|
||||
"Art root does not exist."));
|
||||
return issues;
|
||||
}
|
||||
|
||||
string defaultDirectory = Path.Combine(artRoot, DefaultFolderName);
|
||||
ValidateDirectoryExists(
|
||||
defaultDirectory,
|
||||
LocalizedObjSpriteNaming.DefaultLocaleCode,
|
||||
issues);
|
||||
|
||||
var localizedRelativePaths = new HashSet<string>(
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
foreach (LocalizedObjSpriteDirectory directory in LocaleDirectories)
|
||||
{
|
||||
string localeDirectory = Path.Combine(artRoot, directory.FolderName);
|
||||
if (!ValidateDirectoryExists(localeDirectory, directory.LocaleCode, issues))
|
||||
continue;
|
||||
|
||||
foreach (string filePath in Directory.EnumerateFiles(
|
||||
localeDirectory,
|
||||
"*.png",
|
||||
SearchOption.AllDirectories))
|
||||
{
|
||||
localizedRelativePaths.Add(GetRelativePath(localeDirectory, filePath));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string relativePath in localizedRelativePaths.OrderBy(
|
||||
path => path,
|
||||
StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
ValidateRequiredFile(
|
||||
Path.Combine(defaultDirectory, relativePath),
|
||||
LocalizedObjSpriteNaming.DefaultLocaleCode,
|
||||
issues);
|
||||
|
||||
foreach (LocalizedObjSpriteDirectory directory in LocaleDirectories)
|
||||
{
|
||||
ValidateRequiredFile(
|
||||
Path.Combine(artRoot, directory.FolderName, relativePath),
|
||||
directory.LocaleCode,
|
||||
issues);
|
||||
}
|
||||
}
|
||||
|
||||
if (validateAddressables)
|
||||
ValidateAddressableConfiguration(issues);
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
[MenuItem(ConfigureMenuPath)]
|
||||
public static void ConfigureAddressables()
|
||||
{
|
||||
AddressableAssetSettings settings =
|
||||
AddressableAssetSettingsDefaultObject.Settings;
|
||||
if (settings == null)
|
||||
throw new InvalidOperationException("AddressableAssetSettings does not exist.");
|
||||
|
||||
foreach (LocalizedObjSpriteDirectory directory in LocaleDirectories)
|
||||
{
|
||||
string assetPath = $"{DefaultArtRoot}/{directory.FolderName}";
|
||||
EnsureAssetFolder(assetPath);
|
||||
|
||||
AddressableAssetGroup group = settings.FindGroup(directory.GroupName);
|
||||
if (group == null)
|
||||
{
|
||||
group = settings.CreateGroup(
|
||||
directory.GroupName,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
typeof(BundledAssetGroupSchema),
|
||||
typeof(ContentUpdateGroupSchema));
|
||||
}
|
||||
|
||||
ConfigureGroup(settings, group);
|
||||
|
||||
string guid = AssetDatabase.AssetPathToGUID(assetPath);
|
||||
AddressableAssetEntry entry =
|
||||
settings.CreateOrMoveEntry(guid, group, false, false);
|
||||
entry.address = directory.AddressRoot;
|
||||
}
|
||||
|
||||
settings.SetDirty(
|
||||
AddressableAssetSettings.ModificationEvent.BatchModification,
|
||||
null,
|
||||
true,
|
||||
true);
|
||||
EditorUtility.SetDirty(settings);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log(
|
||||
"[LocalizedObjSpriteValidator] Localized Obj folders and " +
|
||||
"Addressable groups configured.");
|
||||
}
|
||||
|
||||
public static void ConfigureFromCommandLine()
|
||||
{
|
||||
ConfigureAddressables();
|
||||
}
|
||||
|
||||
internal static void LogIssues(
|
||||
IReadOnlyList<LocalizedObjSpriteValidationIssue> issues)
|
||||
{
|
||||
foreach (LocalizedObjSpriteValidationIssue issue in issues)
|
||||
Debug.LogError($"[LocalizedObjSpriteValidator] {issue}");
|
||||
}
|
||||
|
||||
private static void ConfigureGroup(
|
||||
AddressableAssetSettings settings,
|
||||
AddressableAssetGroup group)
|
||||
{
|
||||
BundledAssetGroupSchema bundled =
|
||||
group.GetSchema<BundledAssetGroupSchema>() ??
|
||||
group.AddSchema<BundledAssetGroupSchema>();
|
||||
bundled.BuildPath.SetVariableByName(
|
||||
settings,
|
||||
AddressableAssetSettings.kLocalBuildPath);
|
||||
bundled.LoadPath.SetVariableByName(
|
||||
settings,
|
||||
AddressableAssetSettings.kLocalLoadPath);
|
||||
bundled.IncludeInBuild = true;
|
||||
bundled.Compression = BundledAssetGroupSchema.BundleCompressionMode.LZ4;
|
||||
bundled.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether;
|
||||
EditorUtility.SetDirty(bundled);
|
||||
|
||||
ContentUpdateGroupSchema contentUpdate =
|
||||
group.GetSchema<ContentUpdateGroupSchema>() ??
|
||||
group.AddSchema<ContentUpdateGroupSchema>();
|
||||
contentUpdate.StaticContent = false;
|
||||
EditorUtility.SetDirty(contentUpdate);
|
||||
EditorUtility.SetDirty(group);
|
||||
}
|
||||
|
||||
private static void ValidateAddressableConfiguration(
|
||||
ICollection<LocalizedObjSpriteValidationIssue> issues)
|
||||
{
|
||||
AddressableAssetSettings settings =
|
||||
AddressableAssetSettingsDefaultObject.Settings;
|
||||
if (settings == null)
|
||||
{
|
||||
issues.Add(new LocalizedObjSpriteValidationIssue(
|
||||
"Assets/AddressableAssetsData",
|
||||
"AddressableAssetSettings does not exist."));
|
||||
return;
|
||||
}
|
||||
|
||||
ValidateAddressableFolder(
|
||||
settings,
|
||||
$"{DefaultArtRoot}/{DefaultFolderName}",
|
||||
LocalizedObjSpriteNaming.DefaultAddressRoot,
|
||||
DefaultGroupName,
|
||||
false,
|
||||
issues);
|
||||
|
||||
foreach (LocalizedObjSpriteDirectory directory in LocaleDirectories)
|
||||
{
|
||||
ValidateAddressableFolder(
|
||||
settings,
|
||||
$"{DefaultArtRoot}/{directory.FolderName}",
|
||||
directory.AddressRoot,
|
||||
directory.GroupName,
|
||||
true,
|
||||
issues);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ValidateAddressableFolder(
|
||||
AddressableAssetSettings settings,
|
||||
string assetPath,
|
||||
string expectedAddress,
|
||||
string expectedGroup,
|
||||
bool validateGroupSchema,
|
||||
ICollection<LocalizedObjSpriteValidationIssue> issues)
|
||||
{
|
||||
string guid = AssetDatabase.AssetPathToGUID(assetPath);
|
||||
AddressableAssetEntry entry = string.IsNullOrEmpty(guid)
|
||||
? null
|
||||
: settings.FindAssetEntry(guid);
|
||||
if (entry == null)
|
||||
{
|
||||
issues.Add(new LocalizedObjSpriteValidationIssue(
|
||||
assetPath,
|
||||
"Folder is not registered as an Addressable entry."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.Equals(entry.address, expectedAddress, StringComparison.Ordinal))
|
||||
{
|
||||
issues.Add(new LocalizedObjSpriteValidationIssue(
|
||||
assetPath,
|
||||
$"Address is '{entry.address}', expected '{expectedAddress}'."));
|
||||
}
|
||||
|
||||
AddressableAssetGroup group = entry.parentGroup;
|
||||
if (group == null || !string.Equals(
|
||||
group.Name,
|
||||
expectedGroup,
|
||||
StringComparison.Ordinal))
|
||||
{
|
||||
issues.Add(new LocalizedObjSpriteValidationIssue(
|
||||
assetPath,
|
||||
$"Group is '{group?.Name ?? "<null>"}', expected '{expectedGroup}'."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateGroupSchema)
|
||||
return;
|
||||
|
||||
BundledAssetGroupSchema bundled = group.GetSchema<BundledAssetGroupSchema>();
|
||||
if (bundled == null ||
|
||||
!bundled.IncludeInBuild ||
|
||||
bundled.Compression != BundledAssetGroupSchema.BundleCompressionMode.LZ4 ||
|
||||
bundled.BundleMode != BundledAssetGroupSchema.BundlePackingMode.PackTogether ||
|
||||
bundled.BuildPath.GetName(settings) != AddressableAssetSettings.kLocalBuildPath ||
|
||||
bundled.LoadPath.GetName(settings) != AddressableAssetSettings.kLocalLoadPath)
|
||||
{
|
||||
issues.Add(new LocalizedObjSpriteValidationIssue(
|
||||
assetPath,
|
||||
"Addressable group must use local paths, LZ4, Include In Build, and Pack Together."));
|
||||
}
|
||||
|
||||
ContentUpdateGroupSchema contentUpdate =
|
||||
group.GetSchema<ContentUpdateGroupSchema>();
|
||||
if (contentUpdate == null || contentUpdate.StaticContent)
|
||||
{
|
||||
issues.Add(new LocalizedObjSpriteValidationIssue(
|
||||
assetPath,
|
||||
"Addressable group must use non-static content update settings."));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ValidateDirectoryExists(
|
||||
string directoryPath,
|
||||
string localeCode,
|
||||
ICollection<LocalizedObjSpriteValidationIssue> issues)
|
||||
{
|
||||
if (Directory.Exists(directoryPath))
|
||||
return true;
|
||||
|
||||
issues.Add(new LocalizedObjSpriteValidationIssue(
|
||||
ToAssetPath(directoryPath),
|
||||
$"Missing required '{localeCode}' Obj directory."));
|
||||
return false;
|
||||
}
|
||||
|
||||
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 GetRelativePath(string rootPath, string filePath)
|
||||
{
|
||||
string normalizedRoot = Path.GetFullPath(rootPath)
|
||||
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) +
|
||||
Path.DirectorySeparatorChar;
|
||||
string normalizedFile = Path.GetFullPath(filePath);
|
||||
return normalizedFile.Substring(normalizedRoot.Length);
|
||||
}
|
||||
|
||||
private static void EnsureAssetFolder(string path)
|
||||
{
|
||||
string[] segments = path.Split('/');
|
||||
string current = segments[0];
|
||||
for (int index = 1; index < segments.Length; index++)
|
||||
{
|
||||
string next = $"{current}/{segments[index]}";
|
||||
if (!AssetDatabase.IsValidFolder(next))
|
||||
AssetDatabase.CreateFolder(current, segments[index]);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 686ca5acbb6647d4c802ecd2a8ba043d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,128 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AibisDream.EditorTools.Localization;
|
||||
using AibisDream.UI;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace AibisDream.SystemEditor.Tests
|
||||
{
|
||||
public sealed class LocalizedObjSpriteTests
|
||||
{
|
||||
private string temporaryRoot;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
temporaryRoot = Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
"AibisDreamLocalizedObjSpriteTests",
|
||||
Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(temporaryRoot);
|
||||
Directory.CreateDirectory(Path.Combine(
|
||||
temporaryRoot,
|
||||
LocalizedObjSpriteValidator.DefaultFolderName));
|
||||
foreach (LocalizedObjSpriteDirectory directory in
|
||||
LocalizedObjSpriteValidator.LocaleDirectories)
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(
|
||||
temporaryRoot,
|
||||
directory.FolderName));
|
||||
}
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(temporaryRoot) && Directory.Exists(temporaryRoot))
|
||||
Directory.Delete(temporaryRoot, true);
|
||||
}
|
||||
|
||||
[TestCase("zh-Hans", "Sprite/Obj/病历.png")]
|
||||
[TestCase("zh-CN", "Sprite/Obj/病历.png")]
|
||||
[TestCase("en", "Sprite/Obj_en/病历.png")]
|
||||
[TestCase("en-US", "Sprite/Obj_en/病历.png")]
|
||||
[TestCase("ja-JP", "Sprite/Obj_ja-JP/病历.png")]
|
||||
[TestCase("ru-RU", "Sprite/Obj_ru/病历.png")]
|
||||
[TestCase("es-ES", "Sprite/Obj_es/病历.png")]
|
||||
[TestCase("pt-BR", "Sprite/Obj_pt-BR/病历.png")]
|
||||
public void GetKey_UsesCanonicalLocaleDirectory(
|
||||
string localeCode,
|
||||
string expected)
|
||||
{
|
||||
Assert.That(
|
||||
LocalizedObjSpriteNaming.GetKey("病历.png", localeCode),
|
||||
Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CandidateNames_FallBackToUnsuffixedChineseWithoutDuplicates()
|
||||
{
|
||||
Assert.That(
|
||||
LocalizedObjSpriteNaming.GetCandidateKeys("病历.png", "en"),
|
||||
Is.EqualTo(new[]
|
||||
{
|
||||
"Sprite/Obj_en/病历.png",
|
||||
"Sprite/Obj/病历.png"
|
||||
}));
|
||||
Assert.That(
|
||||
LocalizedObjSpriteNaming.GetCandidateKeys("病历.png", "zh-Hans"),
|
||||
Is.EqualTo(new[] { "Sprite/Obj/病历.png" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Validator_IgnoresUnsuffixedOnlySprites()
|
||||
{
|
||||
WriteSprite(
|
||||
LocalizedObjSpriteValidator.DefaultFolderName,
|
||||
"普通图片.png");
|
||||
|
||||
Assert.That(
|
||||
LocalizedObjSpriteValidator.Validate(temporaryRoot, false),
|
||||
Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Validator_RequiresEveryVariantAfterAGroupIsDetected()
|
||||
{
|
||||
WriteCompleteGroup("病历");
|
||||
Assert.That(
|
||||
LocalizedObjSpriteValidator.Validate(temporaryRoot, false),
|
||||
Is.Empty);
|
||||
|
||||
File.Delete(Path.Combine(temporaryRoot, "Obj_ru", "病历.png"));
|
||||
var issues = LocalizedObjSpriteValidator.Validate(temporaryRoot, false);
|
||||
|
||||
Assert.That(issues, Has.Count.EqualTo(1));
|
||||
Assert.That(issues.Single().AssetPath, Does.EndWith("Obj_ru/病历.png"));
|
||||
Assert.That(issues.Single().Message, Does.Contain("'ru'"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProjectLocaleFolders_AreAddressableByConvention()
|
||||
{
|
||||
Assert.That(
|
||||
LocalizedObjSpriteValidator.Validate(),
|
||||
Is.Empty);
|
||||
}
|
||||
|
||||
private void WriteCompleteGroup(string logicalName)
|
||||
{
|
||||
WriteSprite(
|
||||
LocalizedObjSpriteValidator.DefaultFolderName,
|
||||
$"{logicalName}.png");
|
||||
foreach (LocalizedObjSpriteDirectory directory in
|
||||
LocalizedObjSpriteValidator.LocaleDirectories)
|
||||
{
|
||||
WriteSprite(directory.FolderName, $"{logicalName}.png");
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteSprite(string folderName, string relativePath)
|
||||
{
|
||||
string filePath = Path.Combine(temporaryRoot, folderName, relativePath);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
|
||||
File.WriteAllBytes(filePath, Array.Empty<byte>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 212d27ffec81bcb48a886db924f43e1a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -133,7 +133,7 @@ PlayerSettings:
|
||||
vulkanEnableLateAcquireNextImage: 0
|
||||
vulkanEnableCommandBufferRecycling: 1
|
||||
loadStoreDebugModeEnabled: 0
|
||||
bundleVersion: 0.6.1.16-20260731-152037
|
||||
bundleVersion: 0.6.2.1
|
||||
preloadedAssets:
|
||||
- {fileID: 11400000, guid: 0fb2bc2476953fc43a74f0ab8879077c, type: 2}
|
||||
metroInputSource: 0
|
||||
|
||||
Reference in New Issue
Block a user