ネリスさん備忘録

主にUE4の備忘録を残すよ!

【UE4】アンリアルエンジンにおけるMOD実装・対応について ②【備忘録】

前回からの続き

lunanelis.hatenablog.com

今回はSteamCoreというプラグインを使用して解説するが
SteamWorkShopのAPIでもほぼ同等の関数名があるはずなので参考にはなるはず。

www.unrealengine.com

 

今回の目次

 

 

Steamワークショップへのアップロード

前提としてSteamCorePluginの設定でAppIDとDevSteamIDにゲームのAPPIDを指定している必要があるので注意。

SteamWorkshopでは、アップロードするファイル一式の事を「アイテム」という名称で呼んでいる。

 

また、一連の処理はSteamにログインしている必要があるため、スタンドアローンで起動などしてログインしなければいけない。
PIEではおそらくログインできないため。



アップロード手順

  1. アップロードすることを予告するために、"アイテム"の作成を依頼する

  2. "アイテム"の作成が完了したらPublishedFileIDを用いて"アイテム"のアップロード用ハンドルを受け取る

    ConsumerAppIDはSteamにおけるゲームのAPPIDの事。
  3.  MOD名などの基本情報などを前述のハンドルに対して設定する

    1. SetItemTitle:MOD名を設定

    2. SetItemDescription:MODの説明を設定

    3. SetItemVisibility:MODの閲覧範囲の設定

    4. SetItemContent:MODのあるフォルダのパスを設定


      前回の記事で作った.pakファイルのあるフォルダを指定する。
      アップロード用のフォルダを作っておき、そこに.pakファイルをコピーしてくると利便性が良い

      例:D:\Content\CustomMOD
    5. SetItemPreview:サムネ画像のファイルパスを設定

      例:D:\Content\PreviewImage.jpg
    6. SetItemTags:検索用のタグを設定

      これは無くても問題ないが、MODが多く作られた際に整理しやすいため、こちら側で指定させると良い。
      なお、String配列により複数タグを設定可能
  4. 設定したハンドルを元に"アイテム"を送信して完了


MODに限らず、Steamに何らかのものをアップロードする際は大体この流れで行われる。
スクリーンショットなどもほぼ同じ手順でアップロードできる。

なお、画像ではWidgetで指定できるようにしているためTextBoxの値を取得している



 

Steamワークショップからのダウンロード

概要

SteamでのMODの扱いとしては、Steamのワークショップページで気に入ったMODをSubscribeした後にゲーム内で適応するという流れになる。
Noitaではこんな感じ

実はSubScribeを押した時点でSteamの特定のフォルダ(C:\Program Files (x86)\Steam\steamapps\workshop\content\)にMODのフォルダが丸ごと入っているため、ダウンロード自体は完了している。
これを手動で.pakファイルのあるContentフォルダに移すだけでMODの適応が完了するのだが、今回はゲーム内でそれを実装する方法までの説明をする。

SubscribeしたMODの適応手順

  1. Subscribe済みのMODの数分のFieldIDを取得し、アイテムの詳細をSteamにリクエストするためのPublishFileIDs配列を取得

  2. ハンドルを元にリクエストの作成を行う

  3. リクエストにより取得したデータをもとにMODの詳細なデータを引き出す

    Handleは後でMODの詳細を取得するために
    Resultはリクエストが成功したかを判定
    NumResultsReturnedは取得したMODの数を返す

    NumResultsReturnedを使いForLoopを回して、先ほど取得したHandleを引数として渡すGetQueryUGCResultノードで各MODの詳細が入っているデータを引き出す。
    後ろにあるGetQueryUGCPreviewURLノードはサムネ画像のあるURLを返してくれるため、UIで利用する場合はこれを利用する。
    画像URLから画像データを引き出す方法はここでは割愛。

    ForLoopで回しながら配列にADDし、後にこれをForEachで回して1行ずつのUIとして表示している。(LocalTempDetailが上記のUGCDetailListをForEachした後の単品)

    こんな感じにDetailとサムネのURLを渡している。


  4. 引き出したデータの中にあるPublishedFileIDからファイルパスを取得し
    .pakファイルのあるcontentフォルダにコピーしていく

    Detailのデータ(SteamUGCDetails構造体)を分解するとPublishedFileIDがあるため、それをGetItemInstallInfoノードに渡すことでこのMODがインストールされているフォルダを取得できる。
    そのあとはCopyFileノードを使って1つ1つファイルをcontentsフォルダにコピーしていけば完了。


  5. ゲームを再起動する
    MODの中にある.pakファイルはゲーム起動時にロードされるため、基本的に再起動を行う必要がある。
    そのためシステム側からゲームを落としたり、プレイヤーに終了させるように促す必要がある

 

ダウンロードしたMODのインストール

前述の通り、MODはContentフォルダに入っていれば起動時にロードされるため、何もする必要はなくインストールが完了している。

 

インストール済みのMODの削除

地味に問題になるのがMODの削除
起動時にContentフォルダに入っている.pakをロードして適応するという話は以前からしているが、これは当然MODを含めたファイルをゲーム側が「マウント(ロック)している」状態となるため、削除などしようとしても止められてしまう。
マウント状態のままでは削除できないのであれば、アンマウント(ロック状態を解除)してやればいいだけ。

方法は色々あると思うが、自分はPakLoaderPluginを利用してアンマウント後にDeleteDirectoryノードを呼び出すことでMODの削除を実行している。
この方法は削除後にゲームの動作が保証されないため、了後にゲームを終了することを推奨する。

www.unrealengine.com

もちろん、ゲームを終了した後にContentフォルダを直接開き
中にあるMODファイルを消すことでもMODを削除可能なのでそういう対処も可能。

 

あとがき

この説明でわかるのかなぁと思いつつ、とりあえずたたき台でも出さないとなぁという考えで出すだけ出してしまった。

わからないところがあればコメントしてくれれば補足するのでよろしく。

本当はサンプルプロジェクトを出すべきなんだけど、SteamCoreの再配布になっちゃうからどうしてもできないのが残念。

こういうブログ書いてると、どうしても文字数や画像が必要になって縦長になっちゃうのがどうなのかなぁと思う今日この頃なのであった。

動画がやっぱり一番なのかなぁ…