[チュートリアル]Mod制作への第一歩[3.Modlet化]

v2.0

※この記事は、前前回の記事前回の記事を読んでいる前提で話が進みます。まだ見ていない場合は確認してからご覧ください。

はじめに

Mod制作への第一歩」シリーズは本稿が最後となります。

最後は、前回作成したModデータをModlet化して配布可能な状態にまとめます。

Modlet化する意味

最初に、「ソロで遊んだり、公開する気がないならやらなくても問題ない」とお伝えしました。

実際その通りで、Modを公開したりする気がなく自分で遊んだりサーバーを開く分には不要な作業ではあります。

(前回の課題であるアイテム名が英語表記になってしまう件も意図的にお伝えしていませんができる方法はあるので...

私自身も開発初めて1年ぐらいは公開する気もサラサラなかったのでガンガンファイルを上書きして秘伝のタレよろしく継ぎ足しでModを作成していました。

そして、規模が中規模程度に広がった時にある弊害が起きました。それは

「あれ?この機能いつ書き換えたっけ?というか元ってどんな処理だっけ?」

前回ファイルを実際に開いてデータを修正してもらったのでお分かりかと思いますが、Xmlデータはテキストデータでありながら膨大な量があります。

そのデータを直接弄り回していれば当然どんどん変更量が蓄積していき、実装が古い順にどんどん記憶が薄れていきます。

執拗に過去の変更点をメモでも取っておけば上記もまだどうにかなるかもしれません。

過去の私は※災害ともいえる事態に遭遇しました。それは、当時はまだα版だったのでバージョンが

※ゲームのデータの管理上仕方のない事ですが衝撃が強かったのでこういう表現にしています。

a20 -> a21 へアップデートされた時でした。

Steamの仕様上、アップデートがあるとそのファイルが上書き更新されます。察しの良い方ならお分かりかと思います。そう…

あれ…今まで追加してたデータ…ドコ…ドコナノ……

アップデートの際に公式の変更が加わっていたことにより、ファイルが真っ新上書きされてしまいました。

現在は正式版に昇格しましたが、つい最近 v1 -> v2 へアップデートがありました。

つまり、アップデートがある限りXmlファイルへは変更が入り続けると言っても過言ではないわけです。そんな危険なファイルにあなたのModデータを託せますか?

当然、無理です。

なので、そんな悲劇を生まない為にも絶対にModlet化は必須作業といえます。

そもそもModletって?

固有名詞としてよくModletと書いていますが、じゃあそもそもModletって何ぞや?と思われるかもしれません。

簡単に説明すると「Mod部分を変更点のみ切り出して個別で管理するもの」です。

例えば、「石斧v2.0」を追加するModを作ったとします。

完成した後に、やっぱりもう少し別の調整を加えよう となることがあると思います。

その際、あなたがやらなくてはいけない作業は「items.xmlrecipes.xml を開き、膨大な量のXmlから自分の追加/変更した行数を探し当てて修正を加える」必要があります。

アイテムの追加が1つ とかであればそこまで苦でもないでしょう。ですが、変更が多岐に渡る中規模以上のModの開発となると数十・数百のデータを追加することとなりますが、その際にあなたはあの膨大なデータから自分の追加したデータを検索して修正して… となるのはかなり手間であることは明白だと思います。

その点、Modlet化しておくとファイルが大元のXmlファイルとは別で追加する事となる為、自分が記述したXmlコードしか存在しないので後から修正を加えようと思った際にも比較的容易に作業ができます。

じゃあメリットしかなくない?なんで最初からそっちのやり方教えなかったの?」と思われるかもしれません。確かに最初からModlet化する前提で解説を書くことも可能でした。

では、試しに「既存の石斧の攻撃力とブロックへのダメージを変更するMod」の例を記載します。

<?xml version="1.0" encoding="UTF-8" ?>
<Config>
    <set xpath="items/item[@name='meleeToolRepairT0StoneAxe']/effect_group[position() = 1]/passive_effect[@name='EntityDamage'][@operation='base_set']/@value">100</set>
    <set xpath="items/item[@name='meleeToolRepairT0StoneAxe']/effect_group[position() = 1]/passive_effect[@name='BlockDamage'][@operation='base_set']/@value">50</set>
</Config>

上記は、攻撃力を[100]、ブロックへのダメージを[50]にするためのコードです。

…正直石斧のステータス変えるだけでいきなり上のようなコード書けって言われたら私は挫折する気がします。

もし、これが元ファイルを変更して適用する場合は、

これを

こう書き換えるだけで実現できます。

どう考えても最初に一旦Modってどんなもん?と確認するだけなら後者の方が簡単だしすぐ目に見えて変化が確認できるのでまずはMod制作の楽しさを知ってもらいたくて回りくどい説明となっていました。

Modlet化(準備編)

前置きが長くなりましたが、いよいよModlet化について説明していきます。

まず、Modlet化するにあたって事前に準備が1つあります、それは

Modletを配置する場所」の確認及び作成です。

Modletは基本的に7 Days to Die のルートフォルダ内「Mods」フォルダに配置されます。

C:\Program Files (x86)\Steam\steamapps\common\7 Days To Die\Mods

※v2.0では最初から1つ公式のModletが同封されています

Modletの事前準備として以下の工程が必要となります。

  • 「Mods」フォルダ内に、Modletのフォルダを作成する(フォルダ名は自由)
  • 作成したModletフォルダ内に、ファイル「ModInfo.xml」を新規作成する
  • 作成したModletフォルダ内に、フォルダ「Config」を追加する
  • ModInfo.xml」に、Modletの情報を記載する

今回は、Modletフォルダ名を「StrongStoneAxe」として解説を進めます。

上記の状態まで完了したら、次は「ModInfo.xml」を開きます。

そして、とりあえず一旦以下を貼り付けます

<?xml version="1.0" encoding="UTF-8" ?>
<xml>
	<Name value="StrongStoneAxe" />
	<DisplayName value="StrongStoneAxe" />
	<Description value="石斧を強くする" />
	<Author value="Ritoni" />
	<Version value="1.0.0" />
	<Website value="" />
	<SkipWithAntiCheat value="true" />
</xml>

順番に各項目の説明をしますが、1行目の「<?xml version=”1.0″ encoding=”UTF-8″ ?>」に関しては、おまじないみたいなもので今後「.xml」ファイルを作成する際は常に1行目に記述してください。

  • Name: Modletの名称
  • DisplayName: 表示用のModletの名称(表面上で見える項目でもないのでこだわりなければ Name と同じでOK
  • Description: このModletの説明
  • Author: 作成者
  • Version: Modletのバージョン
  • Website: Modlet公開場所等のURL記入場所。なければ “” でOK
  • SkipWithAntiCheat: EACを有効にするかどうか。 true=EAC無効 false=EAC有効

このファイルは、Modletを作る際必ず必要になるファイルです。毎回作る必要があるので覚えておきましょう。

そして、ファイルを保存する際に注意点が1つあります。それはファイルの文字コードです。

メモ帳だと右下に表示があるのですが

これが、「UTF-8」であることを確認してください。

万が一「UTF-8」以外が表示されている場合は、メニューから「名前を付けて保存」を選択し、保存する際の文字コードを選択することができるので「UTF-8」を選択して保存してください。

これもおまじないと思って「.xml」ファイルを作成する際は毎回確認してください。

(ここではなぜUTF-8にしないといけないのかまでは説明しませんが、UTF-8以外で保存するとデータ内の日本語入力が文字化けします)

チェックリスト

  • Modlet関係でファイルを作成する際は、文字コードを「UTF-8」で保存する
  • ModInfo.xml」はModlet毎に必要(テンプレートを作っておくとGood)
  • .xml」ファイル作成時、1行目にはおまじないを記述する                (<?xml version=”1.0″ encoding=”UTF-8″ ?>

Modlet化(実践編)

長らくお疲れさまでした。ようやくModlet化の準備が整ったのでようやく実際のコードを記述する工程へ進みます。

今回のModletの目的は、前回作ったものをそのままModlet化します

  • 石斧Mk.2」の作成
  • 石斧Mk.2」のステータス調整
  • 石斧Mk.2」のレシピ追加
  • 石斧Mk.2」の名称日本語化

上記4工程に分けて説明していきます。

「石斧Mk.2」の作成

Modlet化では基本的に対応したxmlファイルと同じ名前のファイルを作成してその中にコードを記述していくことになります。

まずは、前回修正したファイル「items.xml」を「Modletフォルダ/Config/」に作成します。

作成したらまずおまじないを記述

ModInfo.xml」では説明を省きましたが、xmlファイルはまずファイル全体を括るタグが必要となります。

この大枠のタグ名に特に指定はないため、好きな単語を入れて作成してください。

(大体作者名を入れたりとか、Modletのシリーズを入れたりすることが多いようです。本ブログでは「Config」で統一して説明します)

メインのコードは、この「Config」タグ内に記述していきます。

そして記述する際に重要となるのが「xpath」というシステムです。

挫折する理由の大半がコイツのせいでもあります。

xpath全体についての解説はまた別の記事で解説することにして、今回は使用するものだけ説明を加えます。

今回は「アイテムの追加」が目的なので、xpathの「appendタグ」機能を使います。

そもそも「xpath」とは、

XPath(XML Path Language) とは、
XML文書内の特定の要素や属性を指定・取得するためのパス言語です。

たとえば、HTML や XML のように「ツリー構造」を持つデータに対して、
「●●という名前の要素を探したい」「●●という属性値を持つ要素だけ取り出したい」といったときに使います。

らしいです。(出展:ChatGPTさん)

その中でも色々機能があるのですが、今回は「append(追加する)」機能を使います。

xpathの指定方法ですが、Xmlは基本的にタグの入れ子によって形成されているデータなので、そのタグを順々に指定していくことでデータの中を操作できます。

例えば

<items>
  <item name="Item1">
    <property name="Power" value="10"></property>
  </item>
</items>

みたいなxmlがあった場合、指定できるxpathとしては

  • 1.xpath=“items”
  • 2.xpath=“items/item”
  • 3.xpath=“items/item/property”

の3パターンとなります。

各パターンでそれぞれ以下のxmlを「append」した際の結果は以下の通りです。

追加するxmlデータ)

<item name="meleeToolRepairT0StoneAxe_2"></item>

1.

<append xpath="items">
  <item name="meleeToolRepairT0StoneAxe_2"></item>
</append>
----------------------------------------------------------------------
<items>
  <item name="Item1">
    <property name="Power" value="10"></property>
  </item>
  <item name="meleeToolRepairT0StoneAxe_2"></item>
</items>

2.

<append xpath="items/item">
  <item name="meleeToolRepairT0StoneAxe_2"></item>
</append>
----------------------------------------------------------------------
<items>
  <item name="Item1">
    <property name="Power" value="10"></property>
    <item name="meleeToolRepairT0StoneAxe_2"></item>
  </item>
</items>

3.

<append xpath="items/item/property">
  <item name="meleeToolRepairT0StoneAxe_2"></item>
</append>
----------------------------------------------------------------------
<items>
  <item name="Item1">
    <property name="Power" value="10">
      <item name="meleeToolRepairT0StoneAxe_2"></item>
    </property>
  </item>
</items>

1~3までどの書き方でも処理としては通ってしまいますが、ゲーム内でちゃんと認識されるのは「」のみです。

しかも、起動時に特にエラーも出ないことが多いためパスを間違えていたとしても気づきにくく、「なんで反映されないんだ?」と小一時間考えた結果距離を置いてしまう みたいなことにもなりかねません。

これに関してはもう慣れとしか言いようがなく、何回も書いて覚えていくしかないので気合で覚えてください。

だいぶ脱線しましたが、今度こそ「石斧Mk.2」用の石斧の情報を記述していきます。

まず、前提は前回まで同様「items.xml」から石斧の情報を丸々コピーします。

そして、新規作成したほうの「items.xml」内に以下の「append」タグを追加、その間にペーストしてアイテム名を「meleeToolRepairT0StoneAxe_2」に修正します。

<append xpath="items">
  << ここ >>
</append>

※ Visual Studio Code の機能でitemタグ内の別の階層になっているタグを折りたたんで表示していますが、中身は元の石斧と同等です

ここまで出来たら、ゲームを起動して一度確認してみましょう

ゲームを起動したままであった場合は、一度クライアントごと落としてから再度起動してください。

Modletの存在を読み込むのはゲーム起動時なので、起動中にModletを追加しても認識してくれません。

Modletを認識させた状態で、Modletの中身を修正する分にはワールドの起動だけで再認識しなおしてくれます。

  • Modletフォルダを追加した -> クライアント再起動
  • Modletフォルダ内の「items.xml」を修正した -> ワールド再起動

(困ったらとりあえずクライアント再起動しておけば確実です)

追加されました。

もし追加されなかった場合は、xpathの指定を見直してみてください。

「石斧Mk.2」のステータス調整

次は「石斧Mk.2」のステータスを調整していきます。

今回使用するのは「setattributeタグ(属性を設定する)」です。

前回、ステータスを調整したときは以下の要素の値を修正しました。

                <passive_effect name="EntityDamage" operation="base_set" value="6" tags="perkMiner69r"/>
                <passive_effect name="BlockDamage" operation="base_set" value="22" tags="perkMiner69r"/>

今回はこの値に対してxpathを使用して「value」の値を設定していきます。

まずは、この要素までのパスを調べます。

<items> (アイテム全体のタグなので必須)
  <item> 
    <effect_group>
      <passive_effect /> ココ
    </effect_group>
  </item>
</items>

このようなパスになっていると思います。

ここで1つ問題になってくるのが <items> タグは全体で1つしかないのでパスとして問題ありませんが、次の <item> はアイテムの数だけ存在します。なのでどのアイテムのパスなのかを明確に指定してあげなければなりません。

こういう時に使える書き方として、以下のような書き方があります。

<append xpath="items/item[@name='meleeToolRepairT0StoneAxe_2']">
  <property name="test" value="1" />
</append>

item[@name=’meleeToolRepairT0StoneAxe_2‘]」この記述で、「<item> の中でも、 name の値が meleeToolRepairT0StoneAxe_2 のものを対象とする」という風に書き換えられます。

@name= の後は、必ずダブルクォート(“)ではなくシングルクォート(‘)で囲ってください

こうすることで、例えば以下のようなデータがあった場合

<items>
  <item name="meleeToolRepairT0StoneAxe">
  </item>
  <item name="meleeToolRepairT0StoneAxe_2>
  </item>
  <item name="meleeToolRepairT0StoneAxe_3>
  </item>
</items>

上のappendタグを使用すると、

<items>
  <item name="meleeToolRepairT0StoneAxe">
  </item>
  <item name="meleeToolRepairT0StoneAxe_2>
    <property name="test" value="1" />
  </item>
  <item name="meleeToolRepairT0StoneAxe_3>
  </item>
</items>

となります。

もし「name」を指定をしなかった場合は以下のようになります

<items>
  <item name="meleeToolRepairT0StoneAxe">
    <property name="test" value="1" />
  </item>
  <item name="meleeToolRepairT0StoneAxe_2>
    <property name="test" value="1" />
  </item>
  <item name="meleeToolRepairT0StoneAxe_3>
    <property name="test" value="1" />
  </item>
</items>

全アイテムに同じ内容を適用したい場合などは便利ですが、大抵の場合は特定のアイテムにのみ変更や追加を適用したいと思いますので、対象を絞るのは大事な工程となります。

脱線しましたが、ステータスを調整する際のxpath を記述していきます。

<setattribute xpath="items/item[@name='meleeToolRepairT0StoneAxe_2']/effect_group/passive_effect">
</setattribute>

今回、<effect_group> が2つあります。

1つ目には「name」が指定されているのでそれを使って対象を絞ります

<setattribute xpath="items/item[@name='meleeToolRepairT0StoneAxe_2']/effect_group[@name='meleeToolRepairT0StoneAxe']/passive_effect">
</setattribute>

これで、今ここまでパスが指定されています。

中身を確認すると、今回修正対象の「EntityDamage」「BlockDamage」も複数あります。

                <passive_effect name="EntityDamage" operation="base_set" value="6" tags="perkMiner69r"/>
                <passive_effect name="EntityDamage" operation="perc_add" value=".1,.5" tier="2,6" tags="perkMiner69r"/>
                <passive_effect name="BlockDamage" operation="base_set" value="22" tags="perkMiner69r"/>
                <passive_effect name="BlockDamage" operation="perc_add" value=".15,.75" tier="2,6" tags="perkMiner69r"/>

operation」の値と、「tier」の有無に焦点を当てます。

まず「operation」の違いについては以下の通りです。

  • base_set: そのアイテムの基礎値設定する
  • perc_add: そのアイテムの基礎値に、指定した値を乗算する

と、なっています。(ほかにもoperationは存在しますが、ここでは省きます)

tier」 については、対象のアイテムの品質に関係しており、「tier=”2,6″」となっている場合は、品質が2~6の時にこの効果が有効化される という意味になります。

perc_add」の「value」を確認すると「value=”.15,.75″」と記載がありますが、これは

品質が2の時、攻撃力に 15%(perc_addの場合、値が100倍された値が%となる .15 = 0.15 *100 = 15%)乗算する

品質が6の時、攻撃力に 75%乗算する

といった内容となります。

(品質3,4,5 の時は、 15% ~ 75% の間の数値がそれぞれ設定されます。)

今回は、基礎攻撃力を変えたいので「operation=”base_set”」を対象とします。

<setattribute xpath="items/item[@name='meleeToolRepairT0StoneAxe_2']/effect_group[@name='meleeToolRepairT0StoneAxe']/passive_effect[@name='EntityDamage' and @operation='base_set']">
</setattribute>

<setattribute xpath="items/item[@name='meleeToolRepairT0StoneAxe_2']/effect_group[@name='meleeToolRepairT0StoneAxe']/passive_effect[@name='BlockDamage' and @operation='base_set']">
</setattribute>

上記のように「name が EntityDamage(BlockDamage) かつ operation が base_set」のように複数条件がある場合は「and」を使用して条件がどちらも合致するものを対象とする と記述できます。

(片方だけ合っていれば対象とする場合は「or」を指定することもできます)

これで、現在のターゲットは調整したい対象まで指定できています。

ここから「append」と少し違うところですが、「setattribute」では

<passive_effect name=”EntityDamage” operation=”base_set” value=”6″ tags=”perkMiner69r”/>

この< />の中身に影響を与えられます。

name=”対象のキー名”」という風に指定できます。

キー名というのは、

<passive_effect name=”EntityDamage” operation=”base_set” value=”6″ tags=”perkMiner69r”/>

太字になっている部分です。( キー名=”値” で1つの属性となっています)

今回は「value」が調整対象なので「name=”value”」となります。

<setattribute xpath="items/item[@name='meleeToolRepairT0StoneAxe_2']/effect_group[@name='meleeToolRepairT0StoneAxe']/passive_effect[@name='EntityDamage' and @operation='base_set']" name="value">100</setattribute>

<setattribute xpath="items/item[@name='meleeToolRepairT0StoneAxe_2']/effect_group[@name='meleeToolRepairT0StoneAxe']/passive_effect[@name='BlockDamage' and @operation='base_set']" name="value">50</setattribute>

上記が、「石斧Mk.2」のステータスを調整する最終的なコードとなります。

コードを追記して、ゲーム起動してみると…

反映されていますね。

そして、アイコンの設定を忘れていたので以下のコードを追記します。

<append xpath="items/item[@name='meleeToolRepairT0StoneAxe_2']">
    <property name="CustomIcon" value="meleeToolRepairT0StoneAxe"/>
</append>

最終的にこうなりました。

(<item name=”meleeToolRepairT0StoneAxe_2″> の中身は長いので折りたたんでいます)

これで起動しなおすと…

無事、アイコンまで付きました。

「石斧Mk.2」のレシピ追加

レシピの追加は簡単です。「石斧Mk.2」を追加したときのように「append」を使って「石斧」のレシピをコピーしてきましょう。

まずは、Modletフォルダ内「Config」フォルダに「recipes.xml」を新規作成し、おまじないを書きます。

次に、大元の「recipes.xml」より「石斧」のレシピをコピーます。

<recipe name="meleeToolRepairT0StoneAxe" count="1" tags="craftingHarvestingTools,packMuleCrafting">
	<ingredient name="resourceRockSmall" count="2"/>
	<ingredient name="resourceYuccaFibers" count="2"/>
	<ingredient name="resourceWood" count="2"/>
</recipe>

これを「append」で<recipes>に追加します。

その際、レシピ名を「石斧Mk.2」のものに書き換えます

    <append xpath="recipes">
        <recipe name="meleeToolRepairT0StoneAxe_2" count="1" tags="craftingHarvestingTools,packMuleCrafting">
            <ingredient name="resourceRockSmall" count="2"/>
            <ingredient name="resourceYuccaFibers" count="2"/>
            <ingredient name="resourceWood" count="2"/>
        </recipe>
    </append>

ゲームを起動しなおしてレシピ検索します。

追加されました。

「石斧Mk.2」の名称日本語化

ここまでの工程で、前回記事と同等までたどり着きました。

最後に、前回課題だった名称が英語表記のままになっている問題を解決していきます。

まずは、Modletフォルダ内「Config」フォルダに「Localization.txt」を新規作成します。

※注意 このファイルは「.txt」ファイルなのでおまじないは不要ですが、ファイルの文字コードは必ず「UTF-8」で保存してください。でないと文字化けします。

そして、1行目に以下を記述します。

Key,Source,Changes,English,Japanese

これは、「CSV」という形式でデータを保存する為の「ヘッダー」という部分になります。

それぞれの役割を説明すると

  • Key: 文字を登録する際のキー。今回でいう、「石斧Mk.2」のnameである「meleeToolRepairT0StoneAxe_2
  • Source:登録する文字がどこで使われるか。
    今回はアイテムで使用されるので「Item」とする
    ただし、別にここは何を入れても問題なし
  • Changes:新規に登録する文字なのか、元からある文字を変更するのかで記述を変える。
    新規なら「New
    変更なら「Change
    (ただし、これも別に適当でも問題なし)
  • English:英語表示の際に表示したい文字を入力する
  • Japanese:ここに、表示したい日本語文字を入力する

「English」「Japanese」のところは、もし他にも対応したい言語がある場合はカンマで区切って追加することができます。(韓国語なら「koreana」ブラジル語なら「brazilian」とか)

今回のデータ用に行を追加します。

Key,Source,Changes,English,Japanese
meleeToolRepairT0StoneAxe_2,Item,New,Stone Axe Mk.2,石斧Mk.2

※登録する文字の中に、「,(カンマ)」は含めないでください。
 「,(カンマ)」で1区切りと認識されるので、文字中に含めてしまうとそこで文字が途切れて次の列のデータとして認識されてしまいます。

上記を適用したらまたワールドを起動しなおします。すると…

ついに、追加したアイテムを日本語で表示することができました!

余白

これにて、「Mod制作への第一歩」編終了となります。

おそらく、アイテムの追加とそのレシピ追加日本語表示 までは手順を追えば到達できたかと思いますが、その工程(xpathやらappendやらsetattributeやらの仕様)については完全に理解できてはいないと思います。

それも当然だと思います。そもそもこんな記事1つで理解できるような内容であればもっとMod作ってる人増えてるでしょうし…

今回はあくまで実際に手を動かしてModletという1つの作品を作り上げたという実績が大事だと思っています。

完全に理解はできていなくとも、なんとなく「あー、アイテム追加するときはこういう手順ね?」とか、「レシピの追加簡単すぎワロタ」とか思って頂ければ幸いです。

結局のところ、どうやってModlet作るのかの工程だけとりあえず知っておけばあとはデータの理解と仕様の把握を進めるだけで、どんどん色々なものを作れる状態になっています。

もし何かModletを作る際にふと手順が分からなくなったりした際は、本稿を覗いてみて手順の確認にでもご使用ください。

次回以降の投稿では、各機能や各種パラメータについての解説を1つずつ追加していく予定です。
取り急ぎ考えているのは

  • xpathタグの種類とその使い方
  • アイテムなどに設定されている各プロパティの解説
  • passive_effectの種類や活用例

等々考えています。
(時間に暇ができた時にコツコツ追加していくので更新時期は不定期となります)

コメント