using System; using System.IO; using System.Security.Cryptography; using System.Text; using UnityEditor; using UnityEngine; namespace VRC.ExampleCentral.Editor { /// /// Stores the GUID and Hash for each Asset in an Example /// [Serializable] public class AssetInfo { public string GUID { get; private set; } public string Hash { get; private set; } /// /// Initializes a new instance of the class with the specified GUID and hash. /// Used for deserialization, after the hash is computed. /// /// The GUID of the asset. /// The hash of the asset. public AssetInfo(string guid, string hash) { GUID = guid; Hash = hash; } /// /// Initializes a new instance of the class with the specified GUID. /// The hash is computed based on the asset's content. /// /// The GUID of the asset. public AssetInfo(string guid) { GUID = guid; Hash = ComputeAssetHash(guid); } /// /// Computes the hash of the asset based on its content. /// /// The GUID of the asset. /// The computed hash of the asset. private string ComputeAssetHash(string guid) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); string fullPath = Path.Combine(Application.dataPath, assetPath.Substring("Assets/".Length)); if (!File.Exists(fullPath)) return "File Not Found"; try { using FileStream stream = File.OpenRead(fullPath); using SHA256 sha = SHA256.Create(); byte[] hashBytes = sha.ComputeHash(stream); StringBuilder sb = new StringBuilder(); foreach (byte b in hashBytes) sb.Append(b.ToString("X2")); return sb.ToString(); } catch (Exception ex) { Debug.LogError($"Error computing hash for {assetPath}: {ex.Message}"); return "Error"; } } /// /// Serializes the asset to a string, using a pipe character as a separator. /// /// A string representation of the asset's guid and hash. public string Serialize() { return $"{GUID}|{Hash}"; } /// /// Deserializes the asset information from a string. /// /// The serialized data string. /// An instance of . /// Thrown when the serialized data format is invalid. public static AssetInfo Deserialize(string serializedData) { var parts = serializedData.Split('|'); if (parts.Length != 2) throw new ArgumentException("Invalid serialized data format"); return new AssetInfo(parts[0], parts[1]); } } }