Open3
Unityのコードメモ
UnityのEditor拡張でコンソールコマンドを動かす方法。
Editorが固まらないようにTaskで実行する。
コマンドの「console_test」部分を変更して試しましょう。
using System;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using Debug = UnityEngine.Debug;
public class TestConsole
{
private const int DefaultTimeoutInMilliseconds = 500000;
private class ProcessRunnerResult
{
public bool Success { get; set; }
public string Output { get; set; }
public string Error { get; set; }
}
[MenuItem("Hoge/Test Console1")]
static void TestConsole1()
{
Debug.Log("RunTask start");
RunTask((log) =>
{
Debug.Log(log);
});
Debug.Log("RunTask End");
}
static async void RunTask(Action<string> finish)
{
var processStartInfo = new ProcessStartInfo
{
FileName = "console_test",
Arguments = "",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
try
{
var result = await StartAndWaitForExitAsync(processStartInfo, 50000, Debug.Log);
Debug.Log($"Process execution {(result.Success ? "succeeded" : "failed")}");
Debug.Log($"Output: {result.Output}");
Debug.Log($"Error: {result.Error}");
finish("finish!");
}
catch (Exception e)
{
Debug.LogError($"Error executing process: {e.Message}");
}
}
static async Task<ProcessRunnerResult> StartAndWaitForExitAsync(ProcessStartInfo processStartInfo,
int timeoutMs = DefaultTimeoutInMilliseconds, Action<string> onOutputReceived = null)
{
var tcs = new TaskCompletionSource<ProcessRunnerResult>();
await Task.Run(() =>
{
using var process = new Process();
process.StartInfo = processStartInfo;
var sbOutput = new StringBuilder();
var sbError = new StringBuilder();
process.OutputDataReceived += (_, e) =>
{
if (e.Data == null) return;
sbOutput.AppendLine(e.Data);
onOutputReceived?.Invoke(e.Data);
};
process.ErrorDataReceived += (_, e) =>
{
if (e.Data == null) return;
sbError.AppendLine(e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (process.WaitForExit(timeoutMs))
{
tcs.SetResult(new ProcessRunnerResult
{
Success = true,
Error = sbError.ToString(),
Output = sbOutput.ToString()
});
return;
}
try
{
process.Kill();
}
catch
{
// プロセスの終了に失敗した場合は無視
}
tcs.SetResult(new ProcessRunnerResult
{
Success = false,
Error = "Process timed out",
Output = sbOutput.ToString()
});
});
return await tcs.Task;
}
}
概要
Addressableで内部的に割り当てられるdependencyKeyに関するメモ。
Addressable Groupにフォルダ登録で登録したり、Pack Together設定をするとdependencyKeyが同じになる。Pack Separately設定でもフォルダ登録した場合はdependencyKeyが同じになる。
参考
- Addressablesの意図しない依存関係をチェックしたい - Activ8 Tech Blog
- AssetBundle へのグループのパック | Addressables | 1.20.5
- グループ設定 | Addressables | 1.20.5
コード
コードはAddressables | 1.22.2を参照している。
Library/PackageCache/com.unity.addressables@1.22.2/Runtime/ResourceLocators/ContentCatalogData.cs
m_DependencyにdependencyKeyが入っている。
class CompactLocation : IResourceLocation
{
ResourceLocationMap m_Locator;
string m_InternalId;
string m_ProviderId;
object m_Dependency; //これに入っている。getメソッドを作りCatalogダンプ時に表示する
object m_Data;
m_Dependencyを使用してAssetを引いている
public IList<IResourceLocation> Dependencies
{
get
{
if (m_Dependency == null)
return null;
IList<IResourceLocation> results;
m_Locator.Locate(m_Dependency, typeof(object), out results); //ここ
return results;
}
}
dependencyKeyの初期化
public CompactLocation(ResourceLocationMap locator, string internalId, string providerId, object dependencyKey, object data, int depHash, string primaryKey, Type type)
{
m_Locator = locator;
m_InternalId = internalId;
m_ProviderId = providerId;
m_Dependency = dependencyKey; //ここでdependencyKeyが初期化されている
m_Data = data;
m_HashCode = internalId.GetHashCode() * 31 + providerId.GetHashCode();
m_DependencyHashCode = depHash;
m_PrimaryKey = primaryKey;
m_Type = type == null ? typeof(object) : type;
}
}
ここでカタログをロードしている。ここにログを仕込むことでdependencyKeyがどのAssetのセットかを確認できる。
public ResourceLocationMap CreateLocator(string providerSuffix = null)
{
var bucketData = Convert.FromBase64String(m_BucketDataString);
int bucketCount = BitConverter.ToInt32(bucketData, 0);
var buckets = new Bucket[bucketCount];
〜中略〜
for (int i = 0; i < buckets.Length; i++)
{
var bucket = buckets[i];
var key = keys[i];
var locs = new IResourceLocation[bucket.entries.Length];
for (int b = 0; b < bucket.entries.Length; b++)
locs[b] = locations[bucket.entries[b]]; //locs[b]をCompactLocationにキャストして変数をダンプする
locator.Add(key, locs);
}
return locator;
Assetをロードした時に、dependencyKeyでロードされるAssetリストが取得できる。
public bool Locate(object key, Type type, out IList<IResourceLocation> locations)
{
IList<IResourceLocation> locs = null;
if (!this.locations.TryGetValue(key, out locs))
{
locations = null;
return false;
}
//ここでlocsをダンプする
Library/PackageCache/com.unity.addressables@1.22.2/Runtime/AddressablesImpl.cs
Assetロード時に呼び出される箇所。ここにログを仕込めばよい。
こで出力したログの次にLocateのログと合わせて見ると依存関係が確認できる。
public AsyncOperationHandle<TObject> LoadAssetAsync<TObject>(IResourceLocation location)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return TrackHandle(LoadAssetWithChain<TObject>(ChainOperation, location));
return TrackHandle(ResourceManager.ProvideResource<TObject>(location));
}
public AsyncOperationHandle<TObject> LoadAssetAsync<TObject>(object key)
{
QueueEditorUpdateIfNeeded();
if (ShouldChainRequest)
return TrackHandle(LoadAssetWithChain<TObject>(ChainOperation, key));
UnityEditor拡張でファイル保存パスダイアログを表示する
【Unity】【エディタ拡張】保存する先を選択させるパネルを表示する - LIGHT11
var outputPath = EditorUtility.SaveFilePanel("Save File",
"",
"hoge",
"txt");
if (string.IsNullOrEmpty(outputPath)) return;
File.WriteAllText(outputPath, sb.ToString());