Skip to content

Instantly share code, notes, and snippets.

@kankikuchi
Created September 24, 2019 21:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kankikuchi/fe0969e0e9b72f6f629bedf3a23b06e7 to your computer and use it in GitHub Desktop.
Save kankikuchi/fe0969e0e9b72f6f629bedf3a23b06e7 to your computer and use it in GitHub Desktop.
Addressable Assetsのアドレスとラベルを管理する定数クラスを自動生成する【Unity】【Addressable Assets】【エディタ拡張】
// 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;
}
}
// 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