(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]

外部からは値が参照出来ない形に実装されているScriptableObject等の内容を無理やり取得する【Unity】【ScriptableObject】【エディタ拡張】【C#】


このエントリーをはてなブックマークに追加

この記事でのバージョン
Unity 2018.4.8f1


はじめに

アセットストアのアセットや外部SDKなどをUnityで使う際、

ScriptableObjectが使われてる事はよくあります。


そしてそのScriptableObjectの値を使いたいのに、

外部からは取得出来ない形に実装されているという場合は少なくありません。


という事で今回はScriptableObjectの内容をで無理やり取得する方法を3パターンほど紹介する記事です!

なお、ScriptableObject以外のアセットやプログラムに使えるものもあります。

f:id:kan_kikuchi:20190924051920j:plain


なお、どのパターンでも以下のような

privateなフィールドのみを持ったScriptableObjectを例に使っています。

using UnityEngine;

/// <summary>
/// サンプル用のScriptableObject
/// </summary>
public class SampleScriptableObject : ScriptableObject {
 
  //外部から取得できない文字列
  [SerializeField]
  private string _text = "SampleText";
   
  //外部から取得できない数字
  [SerializeField]
  private int _num = 58;
 
}
f:id:kan_kikuchi:20190930051907j:plain



Reflection

C#ではReflectionという機能で

オブジェクトから型情報を得たり、クラスかどうか調べる事が出来ます。



そして、そのReflectionを使えばPublicではないフィールドの値を読むことも可能です。

//ScriptableObjectをロード
var sample = AssetDatabase.LoadAssetAtPath<SampleScriptableObject>("Assets/SampleScriptableObject.asset");
    
//_textというPublicではないフィールドの情報を取得
FieldInfo fieldInfo = sample.GetType().GetField("_text", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance);
    
//_textの値を取得
Debug.Log((string)(fieldInfo.GetValue(sample)));
f:id:kan_kikuchi:20190925052825j:plain



TextAsset

Unityは.txtなどのテキストデータをTextAssetとして読み込む事が出来ます。

なお、Resources以外からアセットをロードする場合はAssetDatabase(エディタ上専用)を使います。



実際にコードにしてみると以下のような感じに。

//テキストを読み込み、内容をログで表示
var textAsset = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/SampleText.txt");
Debug.Log(textAsset.text);
f:id:kan_kikuchi:20190924050230j:plain
f:id:kan_kikuchi:20190924050252j:plain


ただし、ScriptableObjectのようなテキストの拡張子でないものをTextAssetにする事は出来ません。

なので、そういうものをTextAssetで読み込みたい場合は、拡張子を変更したものをコピーして使います。


なお、アセットをコピーしたい場合もAssetDatabase(エディタ上専用)を使います。



実際にコードにしてみると以下のような感じに。

//元のScriptableObjectとそれをテキストデータに変換した時のパス
string scriptableObjectPath = "Assets/SampleScriptableObject.asset";
string textAssetPath        = "Assets/SampleScriptableObject.txt";
    
//ScriptableObjectをテキストデータとしてコピー
AssetDatabase.CopyAsset(scriptableObjectPath, textAssetPath);
    
//テキストデータをロード、内容をログで表示
var textAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(textAssetPath);
Debug.Log(textAsset.text);

//テキストデータを削除
AssetDatabase.DeleteAsset(textAssetPath);
f:id:kan_kikuchi:20190930070003j:plain


ちなみに、例えばマテリアルの内容を無理やり取得するなど、ScriptableObject以外にも使えます。


StreamReader

C#にはStreamReaderという機能があり、これでテキストファイルを読み込む事が出来ます。

もちろんこの機能はUnityでも使えますし、しかもどのアセットでもテキストとして扱えます。


//ScriptableObjectの情報を取得
string assetPath = Path.Combine(Application.dataPath, "SampleScriptableObject.asset");
FileInfo fileInfo = new FileInfo(assetPath);
    
//ScriptableObjectをテキストとして読み込む
using (StreamReader reader = new StreamReader(fileInfo.OpenRead(), Encoding.UTF8)){

  //全テキスト取得
  Debug.Log(reader.ReadToEnd());
      
}
f:id:kan_kikuchi:20190924051317j:plain


もちろん、このやり方もScriptableObject以外でも使えます。