- 引入 UnityGameFramework

- 使用 Luban 替代原来的 UGF 的数据表
This commit is contained in:
huangjun
2026-08-30 18:08:55 +08:00
parent 42ad134759
commit 92bf3e9097
1925 changed files with 362268 additions and 4859 deletions
@@ -0,0 +1,59 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System;
using UnityEditor;
namespace UnityGameFramework.Editor.ResourceTools
{
/// <summary>
/// 资源。
/// </summary>
public sealed class Asset : IComparable<Asset>
{
private Asset(string guid, Resource resource)
{
Guid = guid;
Resource = resource;
}
public string Guid
{
get;
private set;
}
public string Name
{
get
{
return AssetDatabase.GUIDToAssetPath(Guid);
}
}
public Resource Resource
{
get;
set;
}
public int CompareTo(Asset asset)
{
return string.Compare(Guid, asset.Guid, StringComparison.Ordinal);
}
public static Asset Create(string guid)
{
return new Asset(guid, null);
}
public static Asset Create(string guid, Resource resource)
{
return new Asset(guid, resource);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f0147356ab2aa7548b5448288d785afe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
namespace UnityGameFramework.Editor.ResourceTools
{
/// <summary>
/// 资源类型。
/// </summary>
public enum AssetType : byte
{
/// <summary>
/// 未知。
/// </summary>
Unknown = 0,
/// <summary>
/// 存放资源。
/// </summary>
Asset,
/// <summary>
/// 存放场景。
/// </summary>
Scene,
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca96b555ae5b2c34e8cc830446f11525
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,50 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
namespace UnityGameFramework.Editor.ResourceTools
{
/// <summary>
/// 资源加载方式类型。
/// </summary>
public enum LoadType : byte
{
/// <summary>
/// 使用文件方式加载。
/// </summary>
LoadFromFile = 0,
/// <summary>
/// 使用内存方式加载。
/// </summary>
LoadFromMemory,
/// <summary>
/// 使用内存快速解密方式加载。
/// </summary>
LoadFromMemoryAndQuickDecrypt,
/// <summary>
/// 使用内存解密方式加载。
/// </summary>
LoadFromMemoryAndDecrypt,
/// <summary>
/// 使用二进制方式加载。
/// </summary>
LoadFromBinary,
/// <summary>
/// 使用二进制快速解密方式加载。
/// </summary>
LoadFromBinaryAndQuickDecrypt,
/// <summary>
/// 使用二进制解密方式加载。
/// </summary>
LoadFromBinaryAndDecrypt
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f5660cbfaa767b84fbc1ef8799919b26
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,192 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using GameFramework;
using System.Collections.Generic;
namespace UnityGameFramework.Editor.ResourceTools
{
/// <summary>
/// 资源。
/// </summary>
public sealed class Resource
{
private readonly List<Asset> m_Assets;
private readonly List<string> m_ResourceGroups;
private Resource(string name, string variant, string fileSystem, LoadType loadType, bool packed, string[] resourceGroups)
{
m_Assets = new List<Asset>();
m_ResourceGroups = new List<string>();
Name = name;
Variant = variant;
AssetType = AssetType.Unknown;
FileSystem = fileSystem;
LoadType = loadType;
Packed = packed;
foreach (string resourceGroup in resourceGroups)
{
AddResourceGroup(resourceGroup);
}
}
public string Name
{
get;
private set;
}
public string Variant
{
get;
private set;
}
public string FullName
{
get
{
return Variant != null ? Utility.Text.Format("{0}.{1}", Name, Variant) : Name;
}
}
public AssetType AssetType
{
get;
private set;
}
public bool IsLoadFromBinary
{
get
{
return LoadType == LoadType.LoadFromBinary || LoadType == LoadType.LoadFromBinaryAndQuickDecrypt || LoadType == LoadType.LoadFromBinaryAndDecrypt;
}
}
public string FileSystem
{
get;
set;
}
public LoadType LoadType
{
get;
set;
}
public bool Packed
{
get;
set;
}
public static Resource Create(string name, string variant, string fileSystem, LoadType loadType, bool packed, string[] resourceGroups)
{
return new Resource(name, variant, fileSystem, loadType, packed, resourceGroups ?? new string[0]);
}
public Asset[] GetAssets()
{
return m_Assets.ToArray();
}
public Asset GetFirstAsset()
{
return m_Assets.Count > 0 ? m_Assets[0] : null;
}
public void Rename(string name, string variant)
{
Name = name;
Variant = variant;
}
public void AssignAsset(Asset asset, bool isScene)
{
if (asset.Resource != null)
{
asset.Resource.UnassignAsset(asset);
}
AssetType = isScene ? AssetType.Scene : AssetType.Asset;
asset.Resource = this;
m_Assets.Add(asset);
m_Assets.Sort(AssetComparer);
}
public void UnassignAsset(Asset asset)
{
asset.Resource = null;
m_Assets.Remove(asset);
if (m_Assets.Count <= 0)
{
AssetType = AssetType.Unknown;
}
}
public string[] GetResourceGroups()
{
return m_ResourceGroups.ToArray();
}
public bool HasResourceGroup(string resourceGroup)
{
if (string.IsNullOrEmpty(resourceGroup))
{
return false;
}
return m_ResourceGroups.Contains(resourceGroup);
}
public void AddResourceGroup(string resourceGroup)
{
if (string.IsNullOrEmpty(resourceGroup))
{
return;
}
if (m_ResourceGroups.Contains(resourceGroup))
{
return;
}
m_ResourceGroups.Add(resourceGroup);
m_ResourceGroups.Sort();
}
public bool RemoveResourceGroup(string resourceGroup)
{
if (string.IsNullOrEmpty(resourceGroup))
{
return false;
}
return m_ResourceGroups.Remove(resourceGroup);
}
public void Clear()
{
foreach (Asset asset in m_Assets)
{
asset.Resource = null;
}
m_Assets.Clear();
m_ResourceGroups.Clear();
}
private int AssetComparer(Asset a, Asset b)
{
return a.Guid.CompareTo(b.Guid);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d3d5c5d16bedc54c976247a6a5b429e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,635 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
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
{
/// <summary>
/// 资源集合。
/// </summary>
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<string, Resource> m_Resources;
private readonly SortedDictionary<string, Asset> m_Assets;
public ResourceCollection()
{
m_ConfigurationPath = Type.GetConfigurationPath<ResourceCollectionConfigPathAttribute>() ?? Utility.Path.GetRegularPath(Path.Combine(Application.dataPath, "GameFramework/Configs/ResourceCollection.xml"));
m_Resources = new SortedDictionary<string, Resource>(StringComparer.Ordinal);
m_Assets = new SortedDictionary<string, Asset>(StringComparer.Ordinal);
}
public int ResourceCount
{
get
{
return m_Resources.Count;
}
}
public int AssetCount
{
get
{
return m_Assets.Count;
}
}
public event GameFrameworkAction<int, int> OnLoadingResource = null;
public event GameFrameworkAction<int, int> 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;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1736b422b0ea4c46bbaf798d320e6f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,16 @@
//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
namespace UnityGameFramework.Editor.ResourceTools
{
/// <summary>
/// ResourceCollection 配置路径属性。
/// </summary>
public sealed class ResourceCollectionConfigPathAttribute : ConfigPathAttribute
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1eb3245545d87064b814268034cc7af6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: