Created
September 24, 2019 21:18
-
-
Save kankikuchi/fe0969e0e9b72f6f629bedf3a23b06e7 to your computer and use it in GitHub Desktop.
Addressable Assetsのアドレスとラベルを管理する定数クラスを自動生成する【Unity】【Addressable Assets】【エディタ拡張】
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// AddressableAssetAddressClassCreator.cs | |
// http://kan-kikuchi.hatenablog.com/entry/AddressableAssetAddressClassCreator | |
// | |
// Created by kan.kikuchi on 2019.09.16. | |
using System.IO; | |
using System.Linq; | |
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEditor.AddressableAssets.Settings; | |
using UnityEngine; | |
/// <summary> | |
/// AddressableAssetのAddressを管理する定数クラスを自動生成するクラス | |
/// </summary> | |
public class AddressableAssetAddressClassCreator : AssetPostprocessor { | |
//変更をチェックするディレクトリのパス | |
private static readonly string TARGET_DIRECTORY_PATH = "Assets/AddressableAssetsData/AssetGroups"; | |
//定数クラスを生成するディレクトリのパス | |
private static readonly string EXPORT_DIRECTORY_PATH = "Assets/Scripts"; | |
//================================================================================= | |
//変更の監視 | |
//================================================================================= | |
#if !UNITY_CLOUD_BUILD | |
//対象のディレクトリ以下の変更をチェック | |
private static void OnPostprocessAllAssets (string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths){ | |
List<string[]> assetsList = new List<string[]> (){ | |
importedAssets, deletedAssets, movedAssets, movedFromAssetPaths | |
}; | |
List<string> targetDirectoryNameList = new List<string> (){ | |
TARGET_DIRECTORY_PATH, | |
}; | |
//変更があったら定数クラス作成 | |
if(ExistsDirectoryInAssets(assetsList, targetDirectoryNameList)) { | |
Create(); | |
} | |
} | |
//入力されたassetsのパスの中に、親ディレクトリの名前ががtargetDirectoryNameListのものが一つでもあるか | |
private static bool ExistsDirectoryInAssets(List<string[]> assetPathsList, List<string> targetDirectoryNameList){ | |
return assetPathsList | |
.Any (assetPaths => assetPaths | |
.Select (assetPath => Path.GetDirectoryName (assetPath)) | |
.Intersect (targetDirectoryNameList).Any()); | |
} | |
#endif | |
//================================================================================= | |
//作成 | |
//================================================================================= | |
//定数クラス作成 | |
[MenuItem("Tools/Create/AddressableAsset Constants Class")] | |
private static void Create() { | |
//アドレスとラベルをまとめるやつ | |
var addressDict = new Dictionary<string, string>(); | |
var labelDict = new Dictionary<string, string>(); | |
//対象のディレクトリ以下のアセットを全て取得し、アドレスとラベルを記録 | |
foreach (var group in LoadAll<AddressableAssetGroup>(TARGET_DIRECTORY_PATH)) { | |
foreach (var entry in group.entries) { | |
if (addressDict.ContainsKey(entry.address)) { | |
Debug.LogError($"{entry.address}というアドレスが重複しています!"); | |
} | |
addressDict[entry.address] = entry.address; | |
foreach (var label in entry.labels) { | |
labelDict[label] = label; | |
} | |
} | |
} | |
//記録したDictionaryから定数クラスを生成 | |
ConstantsClassCreator.Create("AddressableAssetAddress","AddressableAssetのAddressを管理する定数クラス", EXPORT_DIRECTORY_PATH, addressDict); | |
ConstantsClassCreator.Create("AddressableAssetLabel", "AddressableAssetのLabelを管理する定数クラス", EXPORT_DIRECTORY_PATH, labelDict); | |
} | |
//ディレクトリのパス(Assetsから)と型を設定し、Objectを読み込む。存在しない場合は空のListを返す | |
private static List<T> LoadAll<T>(string directoryPath) where T : Object{ | |
List<T> assetList = new List<T> (); | |
//指定したディレクトリに入っている全ファイルを取得(子ディレクトリも含む) | |
string[] filePathArray = Directory.GetFiles (directoryPath, "*", SearchOption.AllDirectories); | |
//取得したファイルの中からアセットだけリストに追加する | |
foreach (string filePath in filePathArray) { | |
T asset = AssetDatabase.LoadAssetAtPath<T>(filePath); | |
if(asset != null){ | |
assetList.Add (asset); | |
} | |
} | |
return assetList; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// AddressableAssetAddressClassCreator.cs | |
// http://kan-kikuchi.hatenablog.com/entry/AddressableAssetAddressClassCreator | |
// | |
// Created by kan.kikuchi on 2019.09.16. | |
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEditor; | |
/// <summary> | |
/// 定数を管理するクラスを生成するクラス | |
/// </summary> | |
public static class ConstantsClassCreator{ | |
//無効な文字を管理する配列 | |
private static readonly string[] INVALUD_CHARS = { | |
" ", "!", "\"", "#", "$", | |
"%", "&", "\'", "(", ")", | |
"-", "=", "^", "~", "\\", | |
"|", "[", "{", "@", "`", | |
"]", "}", ":", "*", ";", | |
"+", "/", "?", ".", ">", | |
",", "<" | |
}; | |
//定数の区切り文字 | |
private const char DELIMITER = '_'; | |
//型名 | |
private const string STRING_NAME = "string"; | |
private const string INT_NAME = "int"; | |
private const string FLOAT_NAME = "float"; | |
/// <summary> | |
/// 定数を管理するクラスを自動生成する | |
/// </summary> | |
public static void Create<T> (string className, string classInfo, string directoryPath, Dictionary<string, T> valueDict){ | |
//入力された型の判定 | |
string typeName = null; | |
if(typeof(T) == typeof(string)){ | |
typeName = STRING_NAME; | |
} | |
else if(typeof(T) == typeof(int)){ | |
typeName = INT_NAME; | |
} | |
else if(typeof(T) == typeof(float)){ | |
typeName = FLOAT_NAME; | |
} | |
else{ | |
Debug.Log (className + "の作成に失敗しました.想定外の型" + typeof(T).Name + "が入力されました"); | |
return; | |
} | |
//ディクショナリーをソートしたものに | |
SortedDictionary<string, T> sortDict = new SortedDictionary<string, T> (valueDict); | |
//入力された辞書のkeyから無効な文字列を削除して、大文字に_を設定した定数名と同じものに変更し新たな辞書に登録 | |
//次の定数の最大長求めるところで、_を含めたものを取得したいので、先に実行 | |
Dictionary<string, T> newValueDict = new Dictionary<string, T> (); | |
foreach (KeyValuePair<string, T> valuePair in sortDict) { | |
string newKey = RemoveInvalidChars(valuePair.Key); | |
newKey = SetDelimiterBeforeUppercase(newKey); | |
newValueDict [newKey] = valuePair.Value; | |
} | |
//定数名の最大長を取得し、空白数を決定 | |
int keyLengthMax = 0; | |
if(newValueDict.Count > 0){ | |
keyLengthMax = 1 + newValueDict.Keys.Select (key => key.Length).Max (); | |
} | |
//コメント文とクラス名を入力 | |
StringBuilder builder = new StringBuilder (); | |
builder.AppendLine ("/// <summary>"); | |
builder.AppendFormat ("/// {0}", classInfo).AppendLine (); | |
builder.AppendLine ("/// </summary>"); | |
builder.AppendFormat ("public static class {0}", className).AppendLine ("{").AppendLine (); | |
//入力された定数とその値のペアを書き出していく | |
string[] keyArray = newValueDict.Keys.ToArray(); | |
foreach (string key in keyArray) { | |
if (string.IsNullOrEmpty (key)) { | |
continue; | |
} | |
//数字だけのkeyだったらスルー | |
else if (System.Text.RegularExpressions.Regex.IsMatch(key ,@"^[0-9]+$")){ | |
continue; | |
} | |
//keyに半英数字と_以外が含まれていたらスルー | |
else if (!System.Text.RegularExpressions.Regex.IsMatch(key, @"^[_a-zA-Z0-9]+$")){ | |
continue; | |
} | |
//イコールが並ぶ用に空白を調整する | |
string EqualStr = String.Format("{0, " + (keyLengthMax - key.Length).ToString() + "}", "="); | |
//上記で判定した型と定数名を入力 | |
builder.Append ("\t").AppendFormat (@" public const {0} {1} {2} ", typeName, key, EqualStr); | |
//Tがstringの場合は値の前後に"を付ける | |
if (typeName == STRING_NAME) { | |
builder.AppendFormat (@"""{0}"";", newValueDict[key]).AppendLine (); | |
} | |
//Tがfloatの場合は値の後にfを付ける | |
else if (typeName == FLOAT_NAME) { | |
builder.AppendFormat (@"{0}f;", newValueDict[key]).AppendLine (); | |
} | |
else { | |
builder.AppendFormat (@"{0};", newValueDict[key]).AppendLine (); | |
} | |
} | |
builder.AppendLine().AppendLine ("}"); | |
//書き出し、ファイル名はクラス名.cs | |
string exportPath = Path.Combine(directoryPath, className + ".cs"); | |
//書き出し先のディレクトリが無ければ作成 | |
string directoryName = Path.GetDirectoryName (exportPath); | |
if (!Directory.Exists (directoryName)) { | |
Directory.CreateDirectory(directoryName); | |
} | |
File.WriteAllText (exportPath, builder.ToString (), Encoding.UTF8); | |
AssetDatabase.Refresh (ImportAssetOptions.ImportRecursive); | |
Debug.Log (className + "の作成が完了しました"); | |
} | |
/// <summary> | |
/// 無効な文字を削除します | |
/// </summary> | |
private static string RemoveInvalidChars(string str){ | |
Array.ForEach(INVALUD_CHARS, c => str = str.Replace(c, string.Empty)); | |
return str; | |
} | |
/// <summary> | |
/// 区切り文字を大文字の前に設定する | |
/// </summary> | |
private static string SetDelimiterBeforeUppercase(string str){ | |
string conversionStr = ""; | |
for(int strNo = 0; strNo < str.Length; strNo++){ | |
bool isSetDelimiter = true; | |
//最初には設定しない | |
if(strNo == 0){ | |
isSetDelimiter = false; | |
} | |
//小文字か数字なら設定しない | |
else if(char.IsLower(str[strNo]) || char.IsNumber(str[strNo])){ | |
isSetDelimiter = false; | |
} | |
//判定してるの前が大文字なら設定しない(連続大文字の時) | |
else if(char.IsUpper(str[strNo - 1]) && !char.IsNumber(str[strNo])){ | |
isSetDelimiter = false; | |
} | |
//判定してる文字かその文字の前が区切り文字なら設定しない | |
else if(str[strNo] == DELIMITER || str[strNo - 1] == DELIMITER){ | |
isSetDelimiter = false; | |
} | |
//文字設定 | |
if(isSetDelimiter){ | |
conversionStr += DELIMITER.ToString(); | |
} | |
conversionStr += str.ToUpper() [strNo]; | |
} | |
return conversionStr; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment