FOModの作り方(C#スクリプトチュートリアル01)
これまでxmlを使ってFOModを作ってきましたが、今回はC# Scriptという言語を使ってFOModを作ってみます。
C# Scriptの概要
- Nexus Mod Manager、Mod Organizerどちらでも使えます。
- 画面の作成・表示・インストール動作すべてを自力で行う必要があります。
- 事前にコンパイルする必要はありません。FOModフォルダにscirpt.csを配置するとインストール時にコンパイルされます。
- Microsoft Visual Studio C#と互換性があります。
- FOMod用のフレームワーク(枠組み)の元で動作しますので、Visual Studio C#で作成したものをそのまま実行することはできません。部分的に処理をコピペして持ってくるのはOKです。
- .NET Frameworkのクラス群は基本的にどれでも使えるようです。.NET Frameworkの正確なバージョンは不明ですが、おそらく.NET Framework 4ではないかと踏んでいます。
- FOModの実行環境はサンドボックス化(隔離)されていてファイルI/Oを直接行うことはできません。C# Scriptが提供する専用メソッドを使い、限られたファイルにのみアクセスできます。
- 画面を視覚的に作成するエディタは用意されていません。試行錯誤で位置を調整するか、Visual Studioで作成したものをコピペするなどの工夫が必要です。
準備するもの
私は2010 Expressを使っています。
なくても作成できますが、Visual Studio側で動作確認をしてからコピペすることで楽ができます。
今回のお題
2つの体型を持つフォロワーModのFOModを作成します。
- ページ切り替えは無し。
- 体型の選択(UNP/CBBE)ができる。
- 選択肢にマウスを乗せると説明文と画像が表示される。
Modファイル FOModC#Tutor01.zip の構成
FOModC#Tutor01\ 00 Core Files\ meshes\ core-mesh.txt textures\ core-texture.txt 10 CBBE\ cbbe-esp.txt meshes\ cbbe-mesh.txt textures\ cbbe-texture.txt 10 UNP\ unp-esp.txt meshes\ unp-mesh.txt textures\ unp-texture.txt FOMod\ info.xml script.cs Images\ CBBE.jpg Intro.jpg UNP.jpg
info.xmlの作成
<?xml version="1.0" encoding="UTF-16"?> <fomod> <Name>FOMod C# Tutorial 01</Name> <Author>ThinkingSkeever</Author> <Version>0.0</Version> <Website>http://thinkingskeever.hatenablog.com/</Website> <Description> <p>This is FOMod C# script tutorial.</p> </Description> </fomod>
script.csの作成
// FOMod C# script tutorial 01 by ThinkingSkeever using System; using System.Drawing; using System.IO; using System.Text; using System.Windows.Forms; using fomm.Scripting; class Script : BaseScript { private bool bInstalled = false; private Form frmMain; private Label lblDesc; private GroupBox grpBodyTypes; private RadioButton rbUnp; private RadioButton rbCbbe; private PictureBox picPreview; private Button btnExit; private Button btnInstall; private Image imgIntro; private Image imgUnp; private Image imgCbbe; private enum BodyTypes { Unp, Cbbe }; private BodyTypes bodyType = BodyTypes.Unp; const string strModLongName = "FOMod C# Tutor 01"; const string strModShortName = "FOModC#Tutor01"; const string strInstall = "インストール"; const string strBodyTypes = "体型を選択します"; const string strExit = "終了"; const string strUnp = "UNP"; const string strCbbe = "CBBE"; const string strDescIntro = "ダウンロードしてくれてありがとう。\nこれはFOMod C# scriptのチュートリアルです。"; const string strDescUnp = "UNP体型です。\nどちらかといえばスリムな体型です。"; const string strDescCbbe = "CBBE体型です。\nむちむちして肉感的な体型です。"; // // *** Event handlers *** // public bool OnActivate() { InitializeForm(); frmMain.ShowDialog(); return bInstalled; } private void btnExit_Click(object sender, EventArgs e) { frmMain.Close(); } private void btnInstall_Click(object sender, EventArgs e) { InstallFiles(); bInstalled = true; frmMain.Close(); } private void rbUnp_CheckedChanged(object sender, EventArgs e) { bodyType = BodyTypes.Unp; } private void rbUnp_MouseEnter(object sender, EventArgs e) { lblDesc.Text = strDescUnp; picPreview.Image = imgUnp; } private void rbUnp_MouseLeave(object sender, EventArgs e) { lblDesc.Text = strDescIntro; picPreview.Image = imgIntro; } private void rbCbbe_CheckedChanged(object sender, EventArgs e) { bodyType = BodyTypes.Cbbe; } private void rbCbbe_MouseEnter(object sender, EventArgs e) { lblDesc.Text = strDescCbbe; picPreview.Image = imgCbbe; } private void rbCbbe_MouseLeave(object sender, EventArgs e) { lblDesc.Text = strDescIntro; picPreview.Image = imgIntro; } // // *** File installer *** // private void InstallFiles() { CopyDataFolder("00 Core Files/"); if (bodyType == BodyTypes.Unp) CopyDataFolder("10 UNP/"); else CopyDataFolder("10 CBBE/"); } private void CopyDataFolder(string targetFolder) { string folder = targetFolder; if (!folder.EndsWith("/")) { folder += "/"; } foreach(string file in GetFomodFileList()) { if (file.StartsWith(folder, StringComparison.OrdinalIgnoreCase)) { string dest = file.Substring(folder.Length); CopyDataFile(file, dest); } } } // // *** Initializers *** // private Image LoadImage(string filename) { Image img; byte[] data = GetFileFromFomod(filename); using (MemoryStream ms = new MemoryStream(data)) { img = Image.FromStream(ms); } return img; } private void InitializeForm() { int tabIndex = 0; // Load resouces imgIntro = LoadImage("FOMod/Images/intro.jpg"); imgUnp = LoadImage("FOMod/Images/UNP.jpg"); imgCbbe = LoadImage("FOMod/Images/CBBE.jpg"); // Main form frmMain = CreateCustomForm(); frmMain.SuspendLayout(); frmMain.ClientSize = new Size(520, 300); frmMain.FormBorderStyle = FormBorderStyle.FixedSingle; frmMain.MaximizeBox = false; frmMain.MinimizeBox = false; frmMain.Name = strModShortName + "Installer"; frmMain.Text = strModLongName + " Installer"; // Controls lblDesc = new Label(); lblDesc.Name = "lblDesc"; lblDesc.Location = new Point(10, 10); lblDesc.Size = new Size(250, 90); lblDesc.TabIndex = tabIndex++; lblDesc.TabStop = false; lblDesc.UseMnemonic = false; lblDesc.Text = strDescIntro; frmMain.Controls.Add(lblDesc); grpBodyTypes = new GroupBox(); grpBodyTypes.Name = "grpBodyTypes"; grpBodyTypes.Location = new Point(10, 110); grpBodyTypes.Size = new Size(250, 50); grpBodyTypes.TabIndex = tabIndex++; grpBodyTypes.TabStop = false; grpBodyTypes.Text = strBodyTypes; frmMain.Controls.Add(grpBodyTypes); rbUnp = new RadioButton(); rbUnp.Name = "rbUnp"; rbUnp.AutoSize = true; rbUnp.Location = new Point(10, 20); rbUnp.TabIndex = 0; rbUnp.TabStop = true; rbUnp.UseMnemonic = false; rbUnp.Text = strUnp; rbUnp.CheckedChanged += new EventHandler(rbUnp_CheckedChanged); rbUnp.MouseEnter += new EventHandler(rbUnp_MouseEnter); rbUnp.MouseLeave += new EventHandler(rbUnp_MouseLeave); grpBodyTypes.Controls.Add(rbUnp); rbCbbe = new RadioButton(); rbCbbe.Name = "rbCbbe"; rbCbbe.AutoSize = true; rbCbbe.Location = new Point(100, 20); rbCbbe.TabIndex = 1; rbCbbe.TabStop = false; rbCbbe.UseMnemonic = false; rbCbbe.Text = strCbbe; rbCbbe.CheckedChanged += new EventHandler(rbCbbe_CheckedChanged); rbCbbe.MouseEnter += new EventHandler(rbCbbe_MouseEnter); rbCbbe.MouseLeave += new EventHandler(rbCbbe_MouseLeave); grpBodyTypes.Controls.Add(rbCbbe); picPreview = new PictureBox(); picPreview.Name = "picPreview"; picPreview.Location = new Point(270, 0); picPreview.Size = new Size(250, 300); picPreview.TabIndex = tabIndex++; picPreview.TabStop = false; picPreview.Image = imgIntro; picPreview.SizeMode = PictureBoxSizeMode.StretchImage; frmMain.Controls.Add(picPreview); btnExit = new Button(); btnExit.Name = "btnExit"; btnExit.Location = new Point(10, 270); btnExit.Size = new Size(100, 24); btnExit.TabIndex = tabIndex++; btnExit.TabStop = true; btnExit.Text = strExit; btnExit.Click += new EventHandler(btnExit_Click); frmMain.Controls.Add(btnExit); btnInstall = new Button(); btnInstall.Name = "btnInstall"; btnInstall.Location = new Point(160, 270); btnInstall.Size = new Size(100, 24); btnInstall.TabIndex = tabIndex++; btnInstall.TabStop = true; btnInstall.Text = strInstall; btnInstall.Click += new EventHandler(btnInstall_Click); frmMain.Controls.Add(btnInstall); // Redraw frmMain.ResumeLayout(false); frmMain.PerformLayout(); } }
インストール方法
- FOModC#Tutor01フォルダごとZIPファイルなどに圧縮してMod管理ツールでインストールします。
動作確認のポイント
- 体型の選択肢にマウスカーソルを乗せると、説明文と画像が切り替わることを確認します。
- インストールオプションを変えて、対応するダミーファイルがインストールされることを確認します。
解説
C#言語、.NET Frameworkの機能については説明しません。http://dobon.net/vb/dotnet/などの解説サイトを参照してください。
- using fomm.Scripting;
C# Scriptを使うための宣言です。
- class Script : BaseScript
BaseScriptはC# Scriptが提供するインストーラ用クラスのうち、一番基本的なものです。
このクラスの派生クラスとして SkyrimBaseScript, FalloutNewVegasBaseScript といったゲーム特化のクラスが用意されています。
- public bool OnActivate()
インストーラが起動されたときに呼び出されるイベントメソッドです。
このメソッド内でインストーラの初期化、表示、インストールの実行を行います。
インストールが成功した場合はtrueを、インストールが失敗した/キャンセルした場合はfalseを返却します。
- private void InstallFiles()
ここでインストールオプションに応じたファイルをコピーしています。
- private void CopyDataFolder(string targetFolder)
指定したフォルダ以下のファイルをまとめてコピーするメソッドです。
BaseScriptクラスではファイル単体をコピーするCopyDataFileメソッドしか提供していません。
このため、GetFomodFileListメソッドを使ってFOMod内のファイル一覧を取得し、フォルダ名と前方一致させながら該当するファイルをコピーしています。
- private Image LoadImage(string filename)
FOMod内のイメージファイルを読み込むメソッドです。
C# Scriptでは直接的なファイルI/Oが許可されていません。そこで、FOMod内のファイル内容を読み取るGetFileFromFomodメソッドをつかってファイル内容を読み込み、MemoryStreamを経由してImageに変換しています。
- private void InitializeForm()
インストーラの画面を作成しています。おそらくここが一番大変です。
Visual Studio C#でフォームを作成してコピペしてくるのが楽だと思われます。
以上です。