読者です 読者をやめる 読者になる 読者になる

Thinking Skeever

Skyrim/The Witcher 3 Modについてのあれこれ。FoModの作り方、Mod導入時のトラブル事例などのニッチな話を書いていきます。a.k.a. BowmoreLover@nexusmods

FOModの作り方(C#スクリプトTips)

Skyrim FOMod作成

FOMod C# ScriptについてのTips(というか判っていること)を書いておきます。

FOMod内のファイル一覧を取得するメソッド

string[] BaseScript::GetFomodFileList()

FOModからファイルの一覧を取得します。FOModフォルダは除外されます。

  • サンプルコード
string msg;
foreach(string file in GetFomodFileList())
    msg = msg + file + "\r\n";
MessageBox(msg);
  • 実行結果
00 Core Files/meshes/core-mesh.txt
00 Core Files/textures/core-texture.txt
10 CBBE/cbbe-esp.txt
10 CBBE/meshes/cbbe-mesh.txt
10 CBBE/textures/cbbe-texture.txt
10 UNP/unp-esp.txt
10 UNP/meshes/unp-mesh.txt
10 UNP/textures/unp-texture.txt

簡易選択画面を表示するメソッド

int[] BaseScript::Select(string[] strItems, string[] strPreviewPaths, string[] strDescriptions, string strTitle, bool bSelectMany)

項目名、プレビュー画像のパス、説明文の配列を渡して簡易選択画面を表示します。
選択された項目のインデクス(0~)の配列が返却されます。何も選択されない、またはキャンセルされた場合は空の配列が返却されます。

  • サンプルコード
string[] items = { "Follower1", "Follower2", "Follower3" };
string[] previews = { "FOMod/Images/Follower1.jpg", "FOMod/Images/Follower2.jpg", "FOMod/Images/Follower3.jpg" };
string[] descs = { "Follower 1", "Follower 2", "Follower 3" };
int[] sels1 = Select(items, previews, descs, "Select Follower", false);
int[] sels2 = Select(items, previews, descs, "Select Follower", true);
  • 実行結果

 f:id:thinkingskeever:20150501181533j:plain

  • 注意事項
    • NMMでは画面の動きが重くなったり、NMMがUAEすることがあります。

バージョン情報の取得

System.Version BaseScript::GetModManagerVersion()
System.Version BaseScript::GetGameVersion()
System.Version SkyrimBaseScript::GetSkseVersion()

Mod管理ツールSkyrim本体、SKSEのバージョン情報を取得します。

  • サンプルコード
string msg;
Version verSKSE = GetSkseVersion();
if (verSKSE != null)
    msg += ("verSKSE=" + verSKSE.ToString());
Version verGame = GetGameVersion();
if (verGame != null)
    msg += (",verGame=" + verGame.ToString());
Version verModMan = GetModManagerVersion();
if (verModMan != null)
    msg += (",verModMan=" + verModMan.ToString());
MessageBox(msg);
  • 実行結果

NMM0.54.10、MO1.2.18、TESV.exe1.9.32、SKSE1.7.2(skse_1_9_32.dll)の場合

NMMのとき
verSKSE=0.1.7.1,verGame=1.3.22.0,verModMan=0.54.10
MOのとき
verSKSE=0.1.7.1,verModMan=0.47.3
  • 注意事項
    • MOのとき、GetGameVersion()はnullを返却します。
    • NMMのとき、GetGameVersion()はSkyrimLauncher.exeのバージョン情報を返却します。

ファイルの動的生成

bool BaseScript::GenerateDataFile(string strPath, byte[] byteData)

バイト配列を渡しファイルを動的に作成してインストールします。
C# Scriptを使う一番のメリットと思われる機能です。

  • サンプルコード1
string text = "Hello,\r\nWorld!!";
byte[] data = Encoding.GetEncoding("utf-8").GetBytes(text);
GenerateDataFile("Docs/hello.txt", data);
  • サンプルコード1の実行結果

Docs/hello.txtの内容

Hello,
World!!
  • サンプルコード2

FoModに含まれるfontconfig.txtを元に一部フォント名を書き換え、fontconfig.txtを動的に生成します。

FoMod/fontconfig.txtの内容

fontlib "Interface\fonts_console.swf"
fontlib "Interface\fonts_jp.swf"
fontlib "Interface\new_font_jp.swf"
map "$ConsoleFont" = "Arial" Normal
map "$StartMenuFont" = "Skyrim_JP_EveryFont" Normal
map "$DialogueFont" = "Skyrim_JP_EveryFont" Normal
map "$EverywhereFont" = "%%%%REPLACE1%%%%" Normal
map "$EverywhereBoldFont" = "%%%%REPLACE1%%%%" Normal
map "$EverywhereMediumFont" = "%%%%REPLACE1%%%%" Normal
map "$DragonFont" = "Dragon_script" Normal
map "$SkyrimBooks" = "Skyrim_JP_BookFont" Normal
map "$HandwrittenFont" = "%%%%REPLACE2%%%%" Normal
map "$HandwrittenBold" = "%%%%REPLACE2%%%%" Normal
map "$FalmerFont" = "Falmer" Normal
map "$DwemerFont" = "Dwemer" Normal
map "$DaedricFont" = "Daedric" Normal
map "$MageScriptFont" = "Mage Script" Normal
map "$SkyrimSymbolsFont" = "SkyrimSymbols" Normal
map "$SkyrimBooks_UnreadableFont" = "SkyrimBooks_Unreadable" Normal
map "$CreditsFont" = "Futura Condensed" Normal
byte[] data = GetFileFromMod("FOMod/fontconfig.txt");
string strTemplate = Encoding.GetEncoding(0).GetString(data);
string strReplaced = strTemplate.Replace("%%%%REPLACE1%%%%", "New_Gothic_Font");
strReplaced = strReplace.Replace("%%%%REPLACE2%%%%", "New_Tegaki_Font");
byte[] data2 = Encoding.GetEncoding("utf-8").GetBytes(strReplaced);
GenerateDataFile("Interface/fontconfig.txt", data2);
  • 実行結果

Interface/fontconfig.txtの内容

fontlib "Interface\fonts_console.swf"
fontlib "Interface\fonts_jp.swf"
fontlib "Interface\new_font_jp.swf"
map "$ConsoleFont" = "Arial" Normal
map "$StartMenuFont" = "Skyrim_JP_EveryFont" Normal
map "$DialogueFont" = "Skyrim_JP_EveryFont" Normal
map "$EverywhereFont" = "New_Gothic_Font" Normal
map "$EverywhereBoldFont" = "New_Gothic_Font" Normal
map "$EverywhereMediumFont" = "New_Gothic_Font" Normal
map "$DragonFont" = "Dragon_script" Normal
map "$SkyrimBooks" = "Skyrim_JP_BookFont" Normal
map "$HandwrittenFont" = "New_Tegaki_Font" Normal
map "$HandwrittenBold" = "New_Tegaki_Font" Normal
map "$FalmerFont" = "Falmer" Normal
map "$DwemerFont" = "Dwemer" Normal
map "$DaedricFont" = "Daedric" Normal
map "$MageScriptFont" = "Mage Script" Normal
map "$SkyrimSymbolsFont" = "SkyrimSymbols" Normal
map "$SkyrimBooks_UnreadableFont" = "SkyrimBooks_Unreadable" Normal
map "$CreditsFont" = "Futura Condensed" Normal

ファイルの有無をチェック

byte[] BaseScript::GetExistingDataFile(string strPath)

引数で指定されたファイルがDataフォルダにあるかどうかを判定します。
Mod Organizerのとき、Skyrim/Dataフォルダに存在しなくてもMOでアクティブになっていればそのファイルが存在すると判定されます。
つまりMOでは仮想Dataフォルダ展開後にModインストーラが実行されています。

  • サンプルコード
if (DataFileExists("Dawnguard.esm"))
	MessageBox("Dawnguard DLCあり");
if (DataFileExists("Interface/fontconfig.txt"))
	MessageBox("fontconfig.txtあり");

インストールされているプラグインの一覧を取得する

string[] BaseScript::GetAllPlugins()
string[] BaseScript::GetActivePlugins()

インストールされているすべてのプラグインの一覧、インストールされMod管理ツールによってアクティブになっているプラグインの一覧を取得します。
Mod Organizerのとき、Dataフォルダに存在しなくてもMOにインストールされていれば一覧として取得できます。
つまりMOでは仮想Dataフォルダ展開後にModインストーラが実行されています。

  • サンプルコード
string msg;
string[] plugins = GetAllPlugins();
foreach(string p in plugins)
{
    msg += (p + "\r\n");
}
MessageBox(msg);
string msg2;
string[] plugins2 = GetActivePlugins();
foreach(string p in plugins2)
{
    msg2 += (p + "\r\n");
}
MessageBox(msg2);
  • 実行結果
skyrim.esm
update.esm
rskyrimchildren.esm
unofficial skyrim patch.esp
dawnguard.esm
unofficial dawnguard patch.esp
hearthfires.esm
unofficial hearthfire patch.esp
      :


以上

Copyright (C) 2015,2017 ThinkingSkeever, All Rights Reserved.
ブログの記事内に記載されているメーカー名、製品名称等は、日本及びその他の国における各企業の商標または登録商標です。
リンクはご自由に。記事の転載はご遠慮ください。記事を引用する場合はトラックバックするか元のURLを明記してください。