TexturePacker导出的png报警告,一些图片在运行时无法显示。打开png.meta后发现一些spriteId和InternalId为0。
手动点击右上角的Reset后可以解决。那么问题就变成了怎么直接调用reset对应的方法。
1.如何调用Reset
在Untiy提供的CS代码中,把相关的Inspector,editorWindow,improter等相关的看完都没发现对用的内容。
换个思路,在Inspector面板上右键可以添加的方法时ContextMenu的特性。没搜到对应的menu,就自己猜, Assets/Reset Object/Reset,都无法正常执行。放弃,看来Reset比较特殊。
2.直接修改meta文件
通过解析yaml文件,修改个值再序列化回去。但是由于unity的非标准yaml格式,换了几个插件都无法正常保存修改。放弃,可以自己硬编码逐行读取???自己保存???
3.通过Unity自己的SerializedProperty修改
网上找到上面提到的文章,自己生成guid来解决。可以实现但是再点击Reset发现meta文件还是会变化。通过找Unity U2D的方法,找到了生成SpriteId和InternalId的方式。
Unity 版本 2022.3
具体实现
var persistentTypeID = GetPersistentTypeID();
var makeMethod = typeof(AssetImporter).GetMethod("MakeLocalFileIDWithHash", bindingFlags);
var spriteIdGenerateMethod = GetSpriteIDGenerate();
private static Dictionary<string, InternalSpriteInfo> keyValuePairs = new Dictionary<string, InternalSpriteInfo>();
private static BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly;
private const string EmptySpriteId = "00000000000000000800000000000000";
public static void ModifyTexturePacker(string assetPath){
keyValuePairs.Clear();
AssetImporter importer = AssetImporter.GetAtPath(assetPath);
SerializedObject serializedObject = new SerializedObject(importer);
//这个不改也不影响,实际上呢?
SerializedProperty idToNameTable = serializedObject.FindProperty("m_InternalIDToNameTable");
SerializedProperty sprites = serializedObject.FindProperty("m_SpriteSheet.m_Sprites");
SerializedProperty nameFiledTable = serializedObject.FindProperty("m_SpriteSheet.m_NameFileIdTable");
if (sprites.isArray)
{
var arraySize = sprites.arraySize;
for (int i = 0; i < arraySize; i++)
{
var sprite = sprites.GetArrayElementAtIndex(i);
var spriteName = sprite.FindPropertyRelative("m_Name");
var spriteId = sprite.FindPropertyRelative("m_SpriteID");
var internalId = sprite.FindPropertyRelative("m_InternalID");
if (spriteId.stringValue.Equals(EmptySpriteId))
{
//internalId是唯一的,重复调用是相同的,不同图集下同名sprite猜测应该会得到同一个值
var newIntarnalId = (long)makeMethod?.Invoke(null, new object[] { persistentTypeID, spriteName.stringValue, 0 });
var obj = (GUID)spriteIdGenerateMethod?.Invoke(null, new object[] { newIntarnalId });
internalId.longValue = newIntarnalId;
spriteId.stringValue = obj.ToString();
keyValuePairs.Add(spriteName.stringValue, new InternalSpriteInfo { InternalID = newIntarnalId, SpriteID = spriteId.stringValue });
//Debug.Log($"{spriteName.stringValue} = {obj.ToString()}");
}
}
}
if (nameFiledTable.isArray)
{
for (int i = 0; i < nameFiledTable.arraySize; i++)
{
var nameField = nameFiledTable.GetArrayElementAtIndex(i);
var first = nameField.FindPropertyRelative("first");
var second = nameField.FindPropertyRelative("second");
if (keyValuePairs.TryGetValue(first.stringValue, out InternalSpriteInfo id))
{
second.longValue = id.InternalID;
}
}
}
serializedObject.ApplyModifiedProperties();
AssetDatabase.ForceReserializeAssets(new[] { assetPath }, ForceReserializeAssetsOptions.ReserializeMetadata);
AssetDatabase.SaveAssetIfDirty(AssetDatabase.GUIDFromAssetPath(assetPath));
}
private static int GetPersistentTypeID(){
var unityType = typeof(Editor).Assembly.GetType("UnityEditor.UnityType");
var propertyID = unityType.GetProperty("persistentTypeID");
var method = unityType.GetMethod("FindTypeByName", BindingFlags.Public | BindingFlags.Static);
var spriteProper = method.Invoke(null, new object[] { "Sprite" });
var persistentTypeID = (int)propertyID.GetValue(spriteProper);
return persistentTypeID;
}
public static MethodInfo GetSpriteIDGenerate()
{
MethodInfo methodInfo = typeof(GUID).GetMethod("CreateGUIDFromSInt64", bindingFlags);
return methodInfo;
}
测试生成的internalId和spriteId和点击Reset结果一致。