//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 loyalsoft. All rights reserved.
// Homepage: http://www.game7000.com/
// Feedback: http://www.game7000.com/
//------------------------------------------------------------
using GameFramework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using UnityEditor;
using UnityEngine;
namespace UnityGameFramework.Editor.ResourceTools
{
///
/// 资源集合。
///
public sealed class ResourceCollection
{
private const string SceneExtension = ".unity";
private static readonly Regex ResourceNameRegex = new Regex(@"^([A-Za-z0-9\._-]+/)*[A-Za-z0-9\._-]+$");
private static readonly Regex ResourceVariantRegex = new Regex(@"^[a-z0-9_-]+$");
private readonly string m_ConfigurationPath;
private readonly SortedDictionary m_Resources;
private readonly SortedDictionary m_Assets;
public ResourceCollection()
{
m_ConfigurationPath = Type.GetConfigurationPath() ?? Utility.Path.GetRegularPath(Path.Combine(Application.dataPath, "GameFramework/Configs/ResourceCollection.xml"));
m_Resources = new SortedDictionary(StringComparer.Ordinal);
m_Assets = new SortedDictionary(StringComparer.Ordinal);
}
public int ResourceCount
{
get
{
return m_Resources.Count;
}
}
public int AssetCount
{
get
{
return m_Assets.Count;
}
}
public event GameFrameworkAction OnLoadingResource = null;
public event GameFrameworkAction OnLoadingAsset = null;
public event GameFrameworkAction OnLoadCompleted = null;
public void Clear()
{
m_Resources.Clear();
m_Assets.Clear();
}
public bool Load()
{
Clear();
if (!File.Exists(m_ConfigurationPath))
{
return false;
}
try
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(m_ConfigurationPath);
XmlNode xmlRoot = xmlDocument.SelectSingleNode("UnityGameFramework");
XmlNode xmlCollection = xmlRoot.SelectSingleNode("ResourceCollection");
XmlNode xmlResources = xmlCollection.SelectSingleNode("Resources");
XmlNode xmlAssets = xmlCollection.SelectSingleNode("Assets");
XmlNodeList xmlNodeList = null;
XmlNode xmlNode = null;
int count = 0;
xmlNodeList = xmlResources.ChildNodes;
count = xmlNodeList.Count;
for (int i = 0; i < count; i++)
{
if (OnLoadingResource != null)
{
OnLoadingResource(i, count);
}
xmlNode = xmlNodeList.Item(i);
if (xmlNode.Name != "Resource")
{
continue;
}
string name = xmlNode.Attributes.GetNamedItem("Name").Value;
string variant = xmlNode.Attributes.GetNamedItem("Variant") != null ? xmlNode.Attributes.GetNamedItem("Variant").Value : null;
string fileSystem = xmlNode.Attributes.GetNamedItem("FileSystem") != null ? xmlNode.Attributes.GetNamedItem("FileSystem").Value : null;
byte loadType = 0;
if (xmlNode.Attributes.GetNamedItem("LoadType") != null)
{
byte.TryParse(xmlNode.Attributes.GetNamedItem("LoadType").Value, out loadType);
}
bool packed = false;
if (xmlNode.Attributes.GetNamedItem("Packed") != null)
{
bool.TryParse(xmlNode.Attributes.GetNamedItem("Packed").Value, out packed);
}
string[] resourceGroups = xmlNode.Attributes.GetNamedItem("ResourceGroups") != null ? xmlNode.Attributes.GetNamedItem("ResourceGroups").Value.Split(',') : null;
if (!AddResource(name, variant, fileSystem, (LoadType)loadType, packed, resourceGroups))
{
Debug.LogWarning(Utility.Text.Format("Can not add resource '{0}'.", GetResourceFullName(name, variant)));
continue;
}
}
xmlNodeList = xmlAssets.ChildNodes;
count = xmlNodeList.Count;
for (int i = 0; i < count; i++)
{
if (OnLoadingAsset != null)
{
OnLoadingAsset(i, count);
}
xmlNode = xmlNodeList.Item(i);
if (xmlNode.Name != "Asset")
{
continue;
}
string guid = xmlNode.Attributes.GetNamedItem("Guid").Value;
string name = xmlNode.Attributes.GetNamedItem("ResourceName").Value;
string variant = xmlNode.Attributes.GetNamedItem("ResourceVariant") != null ? xmlNode.Attributes.GetNamedItem("ResourceVariant").Value : null;
if (!AssignAsset(guid, name, variant))
{
Debug.LogWarning(Utility.Text.Format("Can not assign asset '{0}' to resource '{1}'.", guid, GetResourceFullName(name, variant)));
continue;
}
}
if (OnLoadCompleted != null)
{
OnLoadCompleted();
}
return true;
}
catch
{
File.Delete(m_ConfigurationPath);
if (OnLoadCompleted != null)
{
OnLoadCompleted();
}
return false;
}
}
public bool Save()
{
try
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.AppendChild(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", null));
XmlElement xmlRoot = xmlDocument.CreateElement("UnityGameFramework");
xmlDocument.AppendChild(xmlRoot);
XmlElement xmlCollection = xmlDocument.CreateElement("ResourceCollection");
xmlRoot.AppendChild(xmlCollection);
XmlElement xmlResources = xmlDocument.CreateElement("Resources");
xmlCollection.AppendChild(xmlResources);
XmlElement xmlAssets = xmlDocument.CreateElement("Assets");
xmlCollection.AppendChild(xmlAssets);
XmlElement xmlElement = null;
XmlAttribute xmlAttribute = null;
foreach (Resource resource in m_Resources.Values)
{
xmlElement = xmlDocument.CreateElement("Resource");
xmlAttribute = xmlDocument.CreateAttribute("Name");
xmlAttribute.Value = resource.Name;
xmlElement.Attributes.SetNamedItem(xmlAttribute);
if (resource.Variant != null)
{
xmlAttribute = xmlDocument.CreateAttribute("Variant");
xmlAttribute.Value = resource.Variant;
xmlElement.Attributes.SetNamedItem(xmlAttribute);
}
if (resource.FileSystem != null)
{
xmlAttribute = xmlDocument.CreateAttribute("FileSystem");
xmlAttribute.Value = resource.FileSystem;
xmlElement.Attributes.SetNamedItem(xmlAttribute);
}
xmlAttribute = xmlDocument.CreateAttribute("LoadType");
xmlAttribute.Value = ((byte)resource.LoadType).ToString();
xmlElement.Attributes.SetNamedItem(xmlAttribute);
xmlAttribute = xmlDocument.CreateAttribute("Packed");
xmlAttribute.Value = resource.Packed.ToString();
xmlElement.Attributes.SetNamedItem(xmlAttribute);
string[] resourceGroups = resource.GetResourceGroups();
if (resourceGroups.Length > 0)
{
xmlAttribute = xmlDocument.CreateAttribute("ResourceGroups");
xmlAttribute.Value = string.Join(",", resourceGroups);
xmlElement.Attributes.SetNamedItem(xmlAttribute);
}
xmlResources.AppendChild(xmlElement);
}
foreach (Asset asset in m_Assets.Values)
{
xmlElement = xmlDocument.CreateElement("Asset");
xmlAttribute = xmlDocument.CreateAttribute("Guid");
xmlAttribute.Value = asset.Guid;
xmlElement.Attributes.SetNamedItem(xmlAttribute);
xmlAttribute = xmlDocument.CreateAttribute("ResourceName");
xmlAttribute.Value = asset.Resource.Name;
xmlElement.Attributes.SetNamedItem(xmlAttribute);
if (asset.Resource.Variant != null)
{
xmlAttribute = xmlDocument.CreateAttribute("ResourceVariant");
xmlAttribute.Value = asset.Resource.Variant;
xmlElement.Attributes.SetNamedItem(xmlAttribute);
}
xmlAssets.AppendChild(xmlElement);
}
string configurationDirectoryName = Path.GetDirectoryName(m_ConfigurationPath);
if (!Directory.Exists(configurationDirectoryName))
{
Directory.CreateDirectory(configurationDirectoryName);
}
xmlDocument.Save(m_ConfigurationPath);
AssetDatabase.Refresh();
return true;
}
catch
{
if (File.Exists(m_ConfigurationPath))
{
File.Delete(m_ConfigurationPath);
}
return false;
}
}
public Resource[] GetResources()
{
return m_Resources.Values.ToArray();
}
public Resource GetResource(string name, string variant)
{
if (!IsValidResourceName(name, variant))
{
return null;
}
Resource resource = null;
if (m_Resources.TryGetValue(GetResourceFullName(name, variant).ToLowerInvariant(), out resource))
{
return resource;
}
return null;
}
public bool HasResource(string name, string variant)
{
if (!IsValidResourceName(name, variant))
{
return false;
}
return m_Resources.ContainsKey(GetResourceFullName(name, variant).ToLowerInvariant());
}
public bool AddResource(string name, string variant, string fileSystem, LoadType loadType, bool packed)
{
return AddResource(name, variant, fileSystem, loadType, packed, null);
}
public bool AddResource(string name, string variant, string fileSystem, LoadType loadType, bool packed, string[] resourceGroups)
{
if (!IsValidResourceName(name, variant))
{
return false;
}
if (!IsAvailableResourceName(name, variant, null))
{
return false;
}
if (fileSystem != null && !ResourceNameRegex.IsMatch(fileSystem))
{
return false;
}
Resource resource = Resource.Create(name, variant, fileSystem, loadType, packed, resourceGroups);
m_Resources.Add(resource.FullName.ToLowerInvariant(), resource);
return true;
}
public bool RenameResource(string oldName, string oldVariant, string newName, string newVariant)
{
if (!IsValidResourceName(oldName, oldVariant) || !IsValidResourceName(newName, newVariant))
{
return false;
}
Resource resource = GetResource(oldName, oldVariant);
if (resource == null)
{
return false;
}
if (oldName == newName && oldVariant == newVariant)
{
return true;
}
if (!IsAvailableResourceName(newName, newVariant, resource))
{
return false;
}
m_Resources.Remove(resource.FullName.ToLowerInvariant());
resource.Rename(newName, newVariant);
m_Resources.Add(resource.FullName.ToLowerInvariant(), resource);
return true;
}
public bool RemoveResource(string name, string variant)
{
if (!IsValidResourceName(name, variant))
{
return false;
}
Resource resource = GetResource(name, variant);
if (resource == null)
{
return false;
}
Asset[] assets = resource.GetAssets();
resource.Clear();
m_Resources.Remove(resource.FullName.ToLowerInvariant());
foreach (Asset asset in assets)
{
m_Assets.Remove(asset.Guid);
}
return true;
}
public bool SetResourceLoadType(string name, string variant, LoadType loadType)
{
if (!IsValidResourceName(name, variant))
{
return false;
}
Resource resource = GetResource(name, variant);
if (resource == null)
{
return false;
}
if ((loadType == LoadType.LoadFromBinary || loadType == LoadType.LoadFromBinaryAndQuickDecrypt || loadType == LoadType.LoadFromBinaryAndDecrypt) && resource.GetAssets().Length > 1)
{
return false;
}
resource.LoadType = loadType;
return true;
}
public bool SetResourcePacked(string name, string variant, bool packed)
{
if (!IsValidResourceName(name, variant))
{
return false;
}
Resource resource = GetResource(name, variant);
if (resource == null)
{
return false;
}
resource.Packed = packed;
return true;
}
public Asset[] GetAssets()
{
return m_Assets.Values.ToArray();
}
public Asset[] GetAssets(string name, string variant)
{
if (!IsValidResourceName(name, variant))
{
return new Asset[0];
}
Resource resource = GetResource(name, variant);
if (resource == null)
{
return new Asset[0];
}
return resource.GetAssets();
}
public Asset GetAsset(string guid)
{
if (string.IsNullOrEmpty(guid))
{
return null;
}
Asset asset = null;
if (m_Assets.TryGetValue(guid, out asset))
{
return asset;
}
return null;
}
public bool HasAsset(string guid)
{
if (string.IsNullOrEmpty(guid))
{
return false;
}
return m_Assets.ContainsKey(guid);
}
public bool AssignAsset(string guid, string name, string variant)
{
if (string.IsNullOrEmpty(guid))
{
return false;
}
if (!IsValidResourceName(name, variant))
{
return false;
}
Resource resource = GetResource(name, variant);
if (resource == null)
{
return false;
}
string assetName = AssetDatabase.GUIDToAssetPath(guid);
if (string.IsNullOrEmpty(assetName))
{
return false;
}
Asset[] assetsInResource = resource.GetAssets();
foreach (Asset assetInResource in assetsInResource)
{
if (assetInResource.Name == assetName)
{
continue;
}
if (assetInResource.Name.ToLowerInvariant() == assetName.ToLowerInvariant())
{
return false;
}
}
bool isScene = assetName.EndsWith(SceneExtension, StringComparison.Ordinal);
if (isScene && resource.AssetType == AssetType.Asset || !isScene && resource.AssetType == AssetType.Scene)
{
return false;
}
Asset asset = GetAsset(guid);
if (resource.IsLoadFromBinary && assetsInResource.Length > 0 && asset != assetsInResource[0])
{
return false;
}
if (asset == null)
{
asset = Asset.Create(guid);
m_Assets.Add(asset.Guid, asset);
}
resource.AssignAsset(asset, isScene);
return true;
}
public bool UnassignAsset(string guid)
{
if (string.IsNullOrEmpty(guid))
{
return false;
}
Asset asset = GetAsset(guid);
if (asset != null)
{
asset.Resource.UnassignAsset(asset);
m_Assets.Remove(asset.Guid);
}
return true;
}
private string GetResourceFullName(string name, string variant)
{
return !string.IsNullOrEmpty(variant) ? Utility.Text.Format("{0}.{1}", name, variant) : name;
}
private bool IsValidResourceName(string name, string variant)
{
if (string.IsNullOrEmpty(name))
{
return false;
}
if (!ResourceNameRegex.IsMatch(name))
{
return false;
}
if (variant != null && !ResourceVariantRegex.IsMatch(variant))
{
return false;
}
return true;
}
private bool IsAvailableResourceName(string name, string variant, Resource current)
{
Resource found = GetResource(name, variant);
if (found != null && found != current)
{
return false;
}
string[] foundPathNames = name.Split('/');
foreach (Resource resource in m_Resources.Values)
{
if (current != null && resource == current)
{
continue;
}
if (resource.Name == name)
{
if (resource.Variant == null && variant != null)
{
return false;
}
if (resource.Variant != null && variant == null)
{
return false;
}
}
if (resource.Name.Length > name.Length
&& resource.Name.IndexOf(name, StringComparison.CurrentCultureIgnoreCase) == 0
&& resource.Name[name.Length] == '/')
{
return false;
}
if (name.Length > resource.Name.Length
&& name.IndexOf(resource.Name, StringComparison.CurrentCultureIgnoreCase) == 0
&& name[resource.Name.Length] == '/')
{
return false;
}
string[] pathNames = resource.Name.Split('/');
for (int i = 0; i < foundPathNames.Length - 1 && i < pathNames.Length - 1; i++)
{
if (foundPathNames[i].ToLowerInvariant() != pathNames[i].ToLowerInvariant())
{
break;
}
if (foundPathNames[i] != pathNames[i])
{
return false;
}
}
}
return true;
}
}
}