2025-03-11 15:30:07 +08:00

243 lines
8.6 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
namespace UnityEditor.Formats.Fbx.Exporter
{
internal class RepairMissingScripts
{
private const string ForumPackageGUID = "2d81c55c4d9d85146b1d2de96e084b63";
private const string AssetStorePackageGUID = "628ffbda3fdf4df4588770785d91a698";
private const string FbxPrefabDLLFileId = "69888640";
private const string IdFormat = "{{fileID: {0}, guid: {1}, type:";
private static List<string> s_searchIDsToReplace;
private static List<string> SearchIDsToReplace
{
get
{
if (s_searchIDsToReplace == null || s_searchIDsToReplace.Count <= 0)
{
s_searchIDsToReplace = new List<string>() {
string.Format(IdFormat, FbxPrefabDLLFileId, ForumPackageGUID),
string.Format(IdFormat, FbxPrefabDLLFileId, AssetStorePackageGUID)
};
}
return s_searchIDsToReplace;
}
}
private string[] m_assetsToRepair;
private string[] AssetsToRepair{
get{
if (m_assetsToRepair == null) {
m_assetsToRepair = FindAssetsToRepair ();
}
return m_assetsToRepair;
}
}
public static string SourceCodeSearchID
{
get
{
var fbxPrefabObj = AssetDatabase.LoadMainAssetAtPath(FindFbxPrefabAssetPath());
string searchID = null;
string guid;
long fileId;
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(fbxPrefabObj, out guid, out fileId))
{
searchID = string.Format(IdFormat, fileId, guid);
}
return searchID;
}
}
#if COM_UNITY_FORMATS_FBX_AS_ASSET
public const string FbxPrefabFile = "/UnityFbxPrefab.dll";
#else
public const string FbxPrefabFile = "Packages/com.unity.formats.fbx/Runtime/FbxPrefab.cs";
#endif
public static string FindFbxPrefabAssetPath()
{
#if COM_UNITY_FORMATS_FBX_AS_ASSET
// Find guids that are scripts that look like FbxPrefab.
// That catches FbxPrefabTest too, so we have to make sure.
var allGuids = AssetDatabase.FindAssets("FbxPrefab t:MonoScript");
string foundPath = "";
foreach (var guid in allGuids) {
var path = AssetDatabase.GUIDToAssetPath(guid);
if (path.EndsWith(FbxPrefabFile)) {
if (!string.IsNullOrEmpty(foundPath)) {
// How did this happen? Anyway, just don't try.
Debug.LogWarning(string.Format("{0} found in multiple places; did you forget to delete one of these?\n{1}\n{2}",
FbxPrefabFile.Substring(1), foundPath, path));
return "";
}
foundPath = path;
}
}
if (string.IsNullOrEmpty(foundPath)) {
Debug.LogWarning(string.Format("{0} not found; are you trying to uninstall {1}?", FbxPrefabFile.Substring(1), ModelExporter.PACKAGE_UI_NAME));
}
return foundPath;
#else
// In Unity 2018.1 and 2018.2.0b7, FindAssets can't find FbxPrefab.cs in a package.
// So we hardcode the path.
var path = FbxPrefabFile;
if (System.IO.File.Exists(System.IO.Path.GetFullPath(path)))
{
return path;
}
else
{
Debug.LogWarningFormat("{0} not found; update FbxPrefabFile variable in FbxExporterRepairMissingScripts.cs to point to FbxPrefab.cs path.", FbxPrefabFile);
return "";
}
#endif
}
public int AssetsToRepairCount
{
get
{
return AssetsToRepair.Length;
}
}
public string[] GetAssetsToRepair(){
return AssetsToRepair;
}
public static string[] FindAssetsToRepair()
{
// search project for assets containing old GUID
// ignore if forced binary
if (UnityEditor.EditorSettings.serializationMode == SerializationMode.ForceBinary) {
return new string[]{};
}
// check all scenes and prefabs
string[] searchFilePatterns = new string[]{ "*.prefab", "*.unity" };
List<string> assetsToRepair = new List<string> ();
foreach (string searchPattern in searchFilePatterns) {
foreach (string file in Directory.GetFiles(Application.dataPath, searchPattern, SearchOption.AllDirectories)) {
if (AssetNeedsRepair (file)) {
assetsToRepair.Add (file);
}
}
}
return assetsToRepair.ToArray ();
}
private static bool AssetNeedsRepair(string filePath)
{
try{
using(var sr = new StreamReader (filePath)){
if(sr.Peek() > -1){
var firstLine = sr.ReadLine();
if(!firstLine.StartsWith("%YAML")){
return false;
}
}
var contents = sr.ReadToEnd();
if (SearchIDsToReplace.Exists(searchId => contents.Contains(searchId)))
{
return true;
}
}
}
catch(IOException e){
Debug.LogError (string.Format ("Failed to check file for component update: {0} (error={1})", filePath, e));
}
return false;
}
public bool ReplaceGUIDInTextAssets ()
{
string sourceCodeSearchID = SourceCodeSearchID;
if(string.IsNullOrEmpty(sourceCodeSearchID))
{
return false;
}
bool replacedGUID = false;
foreach (string file in AssetsToRepair) {
replacedGUID |= ReplaceGUIDInFile (file, sourceCodeSearchID);
}
if (replacedGUID) {
AssetDatabase.Refresh ();
}
return replacedGUID;
}
private static bool ReplaceID(string searchId, string replacementId, ref string line)
{
if (line.Contains(searchId))
{
line = line.Replace(searchId, replacementId);
return true;
}
return false;
}
private static bool ReplaceGUIDInFile (string path, string replacementSearchID)
{
// try to read file, assume it's a text file for now
bool modified = false;
try {
var tmpFile = Path.GetTempFileName();
if(string.IsNullOrEmpty(tmpFile)){
return false;
}
using(var sr = new StreamReader (path)){
// verify that this is a text file
var firstLine = "";
if (sr.Peek () > -1) {
firstLine = sr.ReadLine ();
if (!firstLine.StartsWith ("%YAML")) {
return false;
}
}
using(var sw = new StreamWriter (tmpFile, false)){
if (!string.IsNullOrEmpty (firstLine)) {
sw.WriteLine (firstLine);
}
while (sr.Peek () > -1) {
var line = sr.ReadLine ();
SearchIDsToReplace.ForEach(searchId =>
modified |= ReplaceID(searchId, replacementSearchID, ref line)
);
sw.WriteLine (line);
}
}
}
if (modified) {
File.Delete (path);
File.Move (tmpFile, path);
Debug.LogFormat("Updated FbxPrefab components in file {0}", path);
return true;
} else {
File.Delete (tmpFile);
}
} catch (IOException e) {
Debug.LogError (string.Format ("Failed to replace GUID in file {0} (error={1})", path, e));
}
return false;
}
}
}