UnityroomでAddressablesを使おう!

UnityroomでAddressablesを使おう!

UnityroomでWebGLゲームを公開する際に、リソースをアップロードできないため、通常の方法ではStreamingAssetsやAddressablesが使えません。
しかし、これらの制約を回避し、外部サーバーからリソースを読み込むことで、Addressablesを有効活用できる方法があります。
本記事では、Sakura Internetのウェブアクセラレータ(CDN)を使い、Unityroomでのリソース管理を効率化する手順を紹介します。

WebGLでのStreamingAssetsの読み込み

WebGLビルドでStreamingAssetsを読み込む仕組みは、ビルド後に生成されるWebGL.loader.js で定義されています。

// デバッグビルド時
Module.streamingAssetsUrl = new URL(Module.streamingAssetsUrl, document.URL).href;
// リリースビルド時
l.streamingAssetsUrl=new URL(l.streamingAssetsUrl,document.URL).href

new URL(Module.streamingAssetsUrl, document.URL) で定義されている部分が、デプロイ先のサーバーからの相対パスになっています。
これを、自前のサーバーからリソースを読み込むように変更することで、UnityroomでAddressablesを利用できるようになります。

StreamingAssetsを他サーバーから読み込む手順

UnityのゲームをWebGLでビルドした後に必要な作業は以下の通りです。

  1. StreamingAssetsを自前サーバーにアップロード
    • 外部サーバーからアクセスできるように設定する。
  2. WebGL.loader.jsのStreamingAssets URLを書き換える
    • 自前サーバーのURLに変更。
  3. WebGLビルドをUnityroomにアップロード

StreamingAssetsを自前サーバーにアップロード

アップロード先のURLは、https://【自前サーバー】/assets/【アプリ名】/【アプリバージョン】/StreamingAssets とします。

アプリ名とアプリバージョンを含めることで、複数のアプリやバージョンを同時配信できるようにします。

※アプリバージョンを含めない場合は、更新時に古いVer1.0.0 のアプリで、新しいVer1.0.1のファイルにアクセスして不具合の原因となってしまうので、注意が必要です。

例えば、アプリ LevelUpRun の場合は、https://gamehell.net/assets/LevelUpRun/0.0.29/StreamingAssetsとなります。

外部サーバーからアクセスできるようにする

多くのサーバーでは、セキュリティ上の理由から他サーバーからのリソースアクセスが制限されています。
これを解決するために、CORSの設定を変更し、Unityroomからのアクセスを許可します。

unityroomからのアクセスは、unityroom.com*****.play.unityroom.com の2種類のアクセスがあります。
*****は、アップロードしたアプリごとに異なる値。
そのため、全オリジンを許可する必要があります。

通常は.htaccessなどを編集する必要がありますが、
今回はウェブアクセラレータ(CDN)を使用するので、そちらでCORSの設定します。

ウェブアクセラレータ(CDN)を利用し、アクセス負荷対策をする

Sakura Internetのウェブアクセラレータ(CDN)を利用することで、アクセス負荷を軽減し、外部サーバーからのリソース読み込みを高速化できます。ウェブアクセラレータには500GiBの無償利用枠があり、大容量のファイルや大量のアクセスがない限り、ほぼ無料で利用できます。

ウェブアクセラレータ

ウェブアクセラレータのキャッシュを利用することで、以下のメリットが得られます。

  • レンタルサーバーのアクセス負荷軽減: レンタルサーバーへ直接アクセスする代わりに、キャッシュを利用することで負荷を軽減。
  • ダウンロード速度の向上: キャッシュを利用することで、リソースの読み込み速度が向上。
  • CORS設定が簡単: .htaccessを書き換えなくても管理ツールから設定が可能です。

気をつけるポイントは以下の通りです。

  • キャッシュの管理: CDNのキャッシュは一度配信されたデータを保持するため、元ファイルを変更してもキャッシュがクリアされるまでは変更が反映されません。既存ファイルを更新する場合は、別名でアップロードするか、キャッシュを削除してください。
  • 超過料金の発生: 累計500GiBを超えると課金が始まりますが、Unityroomで1万アクセスを超えることはまれなので、心配する必要はほとんどありません。

無料枠で足りない場合は、Ad-Virtuaなどを導入し、ウェブアクセラレータやサーバー代を稼ぐ方法も検討してください。

ウェブアクセラレータでの設定

以下のリンクを参考に設定してください。
ウェブアクセラレータ マニュアル | さくらのクラウド マニュアル

設定すると、公開ドメイン名が割り振られます。
ウェブアクセラレータ設定

CORSは、全オリジン許可に設定します。
CORS

WebGL.loader.js の StreamingAssets URLを書き換える

最後に、WebGLビルド後のWebGL.loader.jsファイル内のStreamingAssetsのURLを、自前サーバーのURLに書き換えます。
これにより、Unityroom上でも外部サーバーからのリソース読み込みが可能となり、Addressablesが利用できるようになります。

// developビルド時
Module.streamingAssetsUrl = new URL("https://【自前サーバー】/assets/【アプリ名】/【アプリバージョン】/StreamingAssets").href;
// リリースビルド時
l.streamingAssetsUrl=new URL("https://【自前サーバー】/assets/【アプリ名】/【アプリバージョン】/StreamingAssets").href

ウェブアクセラレータを利用する場合は、【自前サーバー】を公開ドメイン名に置き換えます。

アプリ LevelUpRun の場合、次のURLです。

  • 元データ
    • https://gamehell.net/assets/LevelUpRun/0.0.29/StreamingAssets
  • ウェブアクセラレータ(CDN)
    • https://4cdqjr8s.user.webaccel.jp/assets/LevelUpRun/0.0.29/StreamingAssets

URLの書き換えスクリプト

毎回書き換え箇所を検索して、手作業で書き換えるのはミスの元なのでWebGL.loader.jsを書き換えるスクリプトを用意しました。

使い方

  • Editorフォルダ下にスクリプトを配置
  • Projectビューで右クリックのメニューから CreateAppUnityroomLoaderJS を選択し設定ファイルを作成
  • 設定ファイルで、WebGL.loader.jsの元ファイルと書き込み先、BaseURLを指定してください。
    • MakeUnityroomLoaderJs

Inspectorの Make Loader Jsボタンをクリックするか、WebGLでビルドすると自動で書き換え済 WebGL.loader.jsが生成されます。

using System.Linq;
using NaughtyAttributes;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;

/// <summary>
/// Unityroom用、StreamingAssetsを別サーバーから読み込むloader.jsを作成するクラス
/// </summary>
[CreateAssetMenu(
    fileName = "UnityroomLoaderJS",
    menuName = "App/UnityroomLoaderJS")]
public class MakeUnityroomLoaderJs : ScriptableObject
{
    [SerializeField]
    private bool m_enable = true;

    // ビルド時に生成されるWebGL.loader.jsのパス
    [SerializeField]
    private string m_srcFileName = "/Build/WebGL/Build/WebGL.loader.js";

    // Unityroom用に生成するWebGL-unityroom.loader.jsのパス
    [SerializeField]
    private string m_dstFileName = "/Build/WebGL/WebGL-unityroom.loader.js";

    [SerializeField]
    private string m_baseURL = "https://********.user.webaccel.jp/assets/";

    [PostProcessBuild(999)]
    public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
    {
        if (buildTarget == BuildTarget.WebGL) { MakeLoaderJs(); }
    }

    [Button]
    private static void MakeLoaderJs()
    {
        var config = Load<MakeUnityroomLoaderJs>();
        if (config == null || !config.m_enable) { return; }

        // Assetフォルダ下のm_srcFileName 絶対パス
        string srcPath = System.IO.Path.Join(Application.dataPath, "../", config.m_srcFileName);
        string dstPath = System.IO.Path.Join(Application.dataPath, "../", config.m_dstFileName);

        if (!System.IO.File.Exists(srcPath))
        {
            Debug.LogWarning(
                $"[Warn] MakeUnityroomLoaderJs.MakeLoaderJs(): {config.m_srcFileName} is not found");
            return;
        }

        // アプリ名の空白は "-" に置き換える
        string appName = Application.productName.Replace(" ", "-");
        string version = Application.version;

        string url = $"{config.m_baseURL}/{appName}/{version}/StreamingAssets";
        Debug.Log($"MakeLoaderJs(): {url}");

        // scrPathの内容を読み込んで、以下のように正規表現で書き換える
        // 変更前 > /\.streamingAssetsUrl\s=\snew URL(.\.streamingAssetsUrl,\sdocument.URL)\.href/
        // 変更後 > new URL($"{m_baseURL}/{バンドルID}/{バージョン}/StreamingAssets")\.htref
        string srcText = System.IO.File.ReadAllText(srcPath);
        string dstText = System.Text.RegularExpressions.Regex.Replace(
            srcText,
            @"\.streamingAssetsUrl\s*=\s*new URL\(\w+\.streamingAssetsUrl,\s*document.URL\)\.href",
            $".streamingAssetsUrl = new URL(\"{url}\").href");

        Debug.Log($"MakeLoaderJs: {srcPath} → {dstPath}");
        System.IO.File.WriteAllText(dstPath, dstText);
    }

    /// <summary>
    /// T型アセットの最初の一つを返す。
    /// 必ず一つしか無い設定ファイルなどのScriptableObject取得に利用
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    private static T Load<T>() where T : UnityEngine.Object
    {
        string guid     = AssetDatabase.FindAssets("t:" + typeof(T).Name).FirstOrDefault();
        string filePath = AssetDatabase.GUIDToAssetPath(guid);
        if (string.IsNullOrEmpty(filePath))
        {
            Debug.LogWarning($"t:{typeof(T).Name} not found...");
            return null;
        }

        return AssetDatabase.LoadAssetAtPath<T>(filePath);
    }
}

Unityroomへのアップロード

Unityroomに書き換えた方のWebGL.loader.jsをアップロードすれば別サーバーからのStreamingAssets読み込みができます。
アップロード

Unityroomで、StreamingAssets / Addressablesが使えるようになりました。
これで多言語対応のLocalizationパッケージなどAddressablesが必須のパッケージもUnityroomで使えるようになります。