MonoGameでMonoGamePipeline使ってる際に、素のバイナリデータもContent.Loadで読み込みたいなーとなったので、「MonoGame Content Pipeline Extension Project」を使って読み込めるようにしてみました。
VisualStudioやMonoGameのインストール等々は割愛します。
環境は「Windows10+Visual Studio Community 2015+MonoGame 3.5」
MonoGamePipeline用のDLLを作る
プロジェクトを作る
- VisualStudioのメニュー「ファイル」⇒「新規作成」⇒「プロジェクト」と進みます。
- 「インストール済み」⇒「テンプレート」⇒「VisualC#」⇒「MonoGame」⇒「MonoGame Content Pipeline Extension Project」で「作成」
こんな感じになります。
とりあえずビルド通す
以下のように怒られるかもしれません。
「warning MSB3274: プライマリ参照 "MonoGame.Framework" は、".NETFramework,Version=v4.5" フレームワークに対して作成されているため、解決できませんでした。これは現在ターゲットされているフレームワーク ".NETFramework,Version=v4.0" よりも新しいバージョンです。」
対処としては以下です。
- ソリューションエクスプローラーからプロジェクトを右クリックしてプロパティ
- 「アプリケーション」の対象のフレームワークを「.NET Framework 4.5」にします。
- 「ターゲットフレームワークの変更」のダイアログが出たら「はい」
- 再度ビルド
これでビルドは通るはず?
Importerを書く
まずは「ContentImporter1.cs」を触っていきます。
以下はプロジェクト作成時に生成されるコード。
[ContentImporter(".xyz", DisplayName = "XYZ Importer", DefaultProcessor = "ContentProcessor1")]
public class ContentImporter1 : ContentImporter<TInput>
{
public override TInput Import(string filename, ContentImporterContext context)
{
// TODO: process the input object, and return the modified data.
throw new NotImplementedException();
}
}
とりあえずもうバイト配列で出力できりゃいいだろということから以下のように変えます。拡張子はdatにしときます。
「TODO」のところにインポート時にデータを修正したい場合は処理を書くようですが、なにも修正しないので、開いたファイルのバイトデータをそのまま返しますw
[ContentImporter(".dat", DisplayName = "Dat Importer", DefaultProcessor = "ContentProcessor1")]
public class ContentImporter1 : ContentImporter<byte[]>
{
public override byte[] Import(string filename, ContentImporterContext context)
{
FileStream fileStream = new FileStream(filename, FileMode.Open);
BinaryReader reader = new BinaryReader(fileStream, Encoding.UTF8);
return reader.ReadBytes((int)fileStream.Length);
}
}
Importerはこれで終わり。
Processorを書く
お次は「ContentProcessor1.cs」。
以下はプロジェクト作成時に生成されるコード。
[ContentProcessor(DisplayName = "MonoGameContentPipelineExtension1.ContentProcessor1")]
public class ContentProcessor1 : ContentProcessor<TInput, TOutput>
{
public override TOutput Process(TInput input, ContentProcessorContext context)
{
// TODO: process the input object, and return the modified data.
throw new NotImplementedException();
}
}
ContentPipelineのビルド時の処理ですが、ここもやはり素のバイナリデータを返すだけなのでinputされたデータをそのまま返してやります。
[ContentProcessor(DisplayName = "DatProcessor")]
public class ContentProcessor1 : ContentProcessor<byte[], byte[]>
{
public override byte[] Process(byte[] input, ContentProcessorContext context)
{
return input;
}
}
Processorもこれで終わり。
ビルドしてDLLを取り出す
ビルドして問題なければ以下フォルダの中に「MonoGameContentPipelineExtension1.dll」ができています。
MonoGameContentPipelineExtension1/bin/Debug/
あとで使うのでデスクトップにでもコピーしておきましょう。
MonoGamePipelineにDLLを適用してdatファイルをビルドする
適当なMonoGameプロジェクトを作成
- VisualStudioのメニュー「ファイル」⇒「新規作成」⇒「プロジェクト」と進みます。
- 「インストール済み」⇒「テンプレート」⇒「VisualC#」⇒「MonoGame」⇒「MonoGame Windows Project」で「作成」
プロジェクト名をデフォルトの「Game1」で作成したとして進めます。
ContentフォルダにDLLをコピー
- 「Game1Game1Content」フォルダ内に先ほど作成した「MonoGameContentPipelineExtension1.dll」をコピーします。
こんな感じになります。
MonoGamePipelineを開いてDLLを追加する
- 同じフォルダにある「Content.mgcb」をダブルクリックすると、MonoGamePupelineが開きます。
- 左上の「Content」を選択後、左下の「References」をクリックして、右側に表示される「...」をクリックします。
- 「Reference Editor」が表示されるので「Add」をクリックし「MonoGameContentPipelineExtension1.dll」を追加して「OK」をクリックします。
- 1度「MonoGamePipeline」を再起動します(DLLが反映されない)
- 「セーブします?」って聞かれるので「はい」をクリックしてください。
Datファイルを登録する
- 拡張子が「.dat」の読み込みたい適当なバイナリファイルをMonoGamePipelineの左上のカラムにドロップします。
- ここでは「test.dat」というファイルをドロップしたとして進めます。
- プロジェクトフォルダ外のファイルをドロップすると以下のような感じで「プロジェクトフォルダ内にコピーする?」と聞かれるので「OK」を押しましょう。
- 問題なければ以下のように「test.dat」が追加され「Importer」は「Dat Importer」、「Processor」は「DatProcessor」となっているはずです。
- なっていない場合は、DLLの作成か、MonoGamePipelineへのDLLの追加で誤りがあったかもしれませんので見直してみましょう。
- メニューのFileからか、「Ctrl+S」で保存します。
Buildする
- 「MonoGamePipeline」メニューの「Build」から「Build」をクリックします。
- Processorに問題がなければ「Build 1 succeeded, 0 failed.」と表示されます。
MonoGameProjectで読み込む
- さきほど作成した「Game1」プロジェクトをVisualStudioで開き「Game.cs」を開きます。
- LoadContentフォルダに読み込み処理を入れてみます。
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
byte[] data = Content.Load<byte[]>("test");
int hoge = 0;
}
- ファイル名は「test.dat」ではなく「test」なので要注意。
- int hoge あたりにブレークポイントを置いて、ファイルが読み込めたか確認します。
- ビルドして、実行して、読み込んだ「data」のサイズがdatファイルと同じサイズになってればOKです。
- あとは煮るなり焼くなり・・・
自分は「test.dat」が11byteだったので上記のような感じです。
Content.Loadでエラーが出る
- 読み込みファイル名を「test.dat」と、拡張子を入れていませんか?
- プロジェクトをビルド後、以下の位置に「test.xnb」が出力されていますか?
- Game1Game1inWindowsx86DebugContent
- ファイルがない場合、一度Content.mgcaに「test.dat」がキチンと登録されていてビルドに成功しているかを見てみてください。
ということで、長くなりましたが以上です。
ContentPipelineの仕組みが少しだけわかった気がします。