LoginSignup
0
2

More than 5 years have passed since last update.

SkyrimのModをプログラムで生成する - 4 - フィールドを扱う

Last updated at Posted at 2017-04-10

はじめに

この記事は、SkyrimというゲームソフトのModファイルのバリナリ解析とそれを利用してModを生成するC#のコードについて記載していくシリーズ物です。
ファイルフォーマットについての詳しい情報は以下のサイトがあります。(以降UESP)
Tes5Mod:Mod File Format - The Unofficial Elder Scrolls Pages (UESP)

前回はレコードについて扱いましたので、今回はフィールドについてです。

  • グループ
    • レコード
      • フィールド

フィールドクラス

フィールドのヘッダー構成は次の通りです。

項目名 byte数 byte数合計 説明
Signature string 4 4 どのような情報を扱うかを識別する記号。
DataSize ushort 2 6 ヘッダーサイズを含まないフィールドの全体サイズ。

フィールド内でもデータの内容が分かれていたりしますが、後は、構造体として何byte目が何の情報で・・・のように扱うことになります。

    public class TesField : TesBase
    {
        public TesString Signature { get; }
        public TesUInt16 DataSize { get; }
        public TesList<ITesBase> Values { get; } = new TesList<ITesBase>();
        public TesField(TesFileReader fr)
        {
            Signature = new TesString(fr.GetString(4));
            DataSize = new TesUInt16(fr);
            Values.Add(fr.GetBytes(DataSize.Value));
            OutputItems.Add(Signature);
            OutputItems.Add(DataSize);
            OutputItems.Add(Values);
        }
    }

まずは、そのままDataSize分のバイト数を取り込むようにしていますが、後々個別のフィールドを扱うように、一応リストにしておきます。

では、フィールドを扱うようにレコードクラスなどに修正を入れます。

TesRecord
    public class TesRecord : TesBase
    {
        public TesHeader Header { get; }
        public Dictionary<string, TesList<TesField>> Fields { get; } = new Dictionary<string, TesList<TesField>>();

        public TesRecord(TesFileReader fr)
        {
            Header = new TesHeader(fr);
            OutputItems.Add(Header);
            while (!fr.EOF)
            {
                TesField field = ReadField(fr) ?? new TesField(fr.GetField());
                AddField(field);
            }
       }
        public void AddField(TesField field)
        {
            OutputItems.Add(field);
            if (!Fields.ContainsKey(field.Signature))
                Fields.Add(field.Signature, new TesList<TesField>());

            Fields[field.Signature].Add(field);
        }
        public virtual TesField ReadField(TesFileReader fr)
        {
            TesField result = null;

            string id = fr.GetTypeID();
            switch (id)
            {
            }
            return result;
        }
    }
TesFileReader
        public TesFileReader GetField(bool next = true)
        {
            long count = GetUInt16(4, false) + 6;
            TesFileReader result = new TesFileReader(br, pos, pos + count);
            if (next)
                pos += count;

            return result;
        }
        public string GetTypeID(long offset = 0)
        {
            string result = GetString(4, offset, false);
            return result;
        }

レコードクラスはそこそこ手入れをしました。
まず、フィールドについては、出力用のOutputItemsに追加すると共に、SignatureでアクセスできるようにDictionaryに登録することにします。
また、同じSignatureで複数フィールドある場合があるため、リストに追加します。
フィールドの読み取りは、後々レコードクラスを継承して個別のレコードに対応した際に、必要なフィールドを処理できるようにしておきます。
特に、いくつかのフィールドは同じSignatureでも、中身が異なるケースがあるため、注意が必要です。

以上、今回はここまでです。

前回 次回
3 - レコードを扱う 5 - Modファイルを扱う
0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2