Spustenie Unity WebGL s ASP.NET Core

Stránka aktualizovaná :
Dátum vytvorenia strany :

Prostredie overovania

Windows
  • Windows 11
Editor jednoty
  • 2020.3.25f1
Vizuálne štúdio
  • Visual Studio 2022
ASP.NET jadro
  • ASP.NET Core 6.0
Internetové informačné služby (IIS)
  • IIS 10.0

Najskôr

Naučte sa, ako spustiť výstup hry ako WebGL v Unity na webovom serveri ASP.NET Core. V prípade herných programov použite tie, ktoré sú uvedené v krokoch tipov nižšie. Príklad hry používa 2D plošinovku Microgame, ktorú je možné vytvoriť z Unity Hub.

Vysvetlím, ako nastaviť "Uncompressed WebGL", "WebGL compressed with Gzip" a "WebGL compressed with Brotli" na spustenie hier WebGL. Postup je rovnaký pre všetky z nich.

Používame Visual Studio 2022, ASP.NET Core 6.0, ale staršie verzie pravdepodobne budú fungovať. Štruktúra počiatočného kódu je však pre každú verziu odlišná, preto rozdiely pochopte sami.

Vytvorenie ASP.NET základného projektu

Spustite "Visual Studio 2022" z ponuky Štart.

Vyberte položku Vytvoriť nový projekt.

Tentoraz vyberte ako ukážku možnosť "ASP.NET Core Web App". Ak používate ASP.NET Core, môžete spustiť iné šablóny, ale budete musieť postupovať podľa jednotlivých šablón, ako ju vytvoriť.

Ľubovoľne nastavte názov a umiestnenie projektu.

Ďalšie informácie nechajte tak, ako sú.

Projekt bol vytvorený.

Spustenie nekomprimovaného rozhrania WebGL

Pripravte program WebGL vytvorený bez kompresie.

Uistite sa, že hra funguje rýchlo

ASP.NET Skúste spustiť hru WebGL s menším počtom nastavení bez dodržiavania základnej etikety.

V ASP.NET Core nemôžete získať prístup k niektorým súborom WebGL vysielaným Unity v predvolenom stave. Urobte to prístupným.

Program.cs

Otvoriť z Program.cs projektu. Platí pre staršie verzie Startup.cs ASP.NET Core.

Pridajte priestor názvov do hornej časti kódu a v kóde app.UseStaticFiles(); nahraďte nasledovné:

// ここから追加
using Microsoft.AspNetCore.StaticFiles;
// ここまで追加

var builder = WebApplication.CreateBuilder(args);

// --- 省略 ---

app.UseHttpsRedirection();

//app.UseStaticFiles();
// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
});
// ここまで追加

app.UseRouting();

// --- 省略 ---

.data, takže keď je súbor prístupný, .wasm môže byť vrátený klientovi so zadaným Content-Type .

Nasadenie WebGL

Umiestnite do projektu wwwroot nasledujúce priečinky súborov z Unity .

  • index.html
  • Budovať
  • TemplateData

Index.cshtmlindex.html Otvorte prepojenie, aby ste k nemu mali prístup.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<a href="index.html">index.html</a>

Spustite program a uistite sa, že hra funguje.

Spustenie programu WebGL na stránke Razor

Predchádzajúca hra bežala na statickom HTML súbore, takže beží na mieste, ktoré nemá nič spoločné s ASP.NET Core. Nie je to veľmi žiaduce pre jednotnosť programu, takže presunieme správanie súboru HTML na Razor Pages.

Kliknite pravým tlačidlom myši na priečinok Pages v projekte a pridajte novú položku.

Vyberte položku Razor Page - Empty. Nie je špecifikovaný žiadny konkrétny názov, ale je tu WebGL.cshtml pridaný .

Zobrazí sa kód.

index.html Pozrite si obsah súboru a port na WebGL.cshtml . link Existuje niekoľko zvláštnych bodov, napríklad ako umiestniť značku, ale kvôli jednoduchosti vysvetlenia to nechám tak, ako to je.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <div id="unity-loading-bar">
    <div id="unity-logo"></div>
    <div id="unity-progress-bar-empty">
      <div id="unity-progress-bar-full"></div>
    </div>
  </div>
  <div id="unity-warning"> </div>
  <div id="unity-footer">
    <div id="unity-webgl-logo"></div>
    <div id="unity-fullscreen-button"></div>
    <div id="unity-build-title">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="TemplateData/favicon.ico">
  <link rel="stylesheet" href="TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    var loadingBar = document.querySelector("#unity-loading-bar");
    var progressBarFull = document.querySelector("#unity-progress-bar-full");
    var fullscreenButton = document.querySelector("#unity-fullscreen-button");
    var warningBanner = document.querySelector("#unity-warning");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == 'warning'の場合、黄色のハイライト色が使用されます。
    // この関数を変更または削除して、重要ではない警告とエラーメッセージがユーザーに表示されるように
    // 視覚的に表示される方法をカスタマイズします。
    function unityShowBanner(msg, type) {
      function updateBannerVisibility() {
        warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
      }
      var div = document.createElement('div');
      div.innerHTML = msg;
      warningBanner.appendChild(div);
      if (type == 'error') div.style = 'background: red; padding: 10px;';
      else {
        if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
        setTimeout(function() {
          warningBanner.removeChild(div);
          updateBannerVisibility();
        }, 5000);
      }
      updateBannerVisibility();
    }

    var buildUrl = "Build";
    var loaderUrl = buildUrl + "/WebGL.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL.data",
      frameworkUrl: buildUrl + "/WebGL.framework.js",
      codeUrl: buildUrl + "/WebGL.wasm",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Index.cshtmlWebGL Pridajte prepojenie na .

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
</ul>

Pokúste sa spustiť program. Môžete vidieť, že hlavička a päta _Layout.cshtml sú zobrazené na stránke WebGL podľa .

Zmena umiestnenia súborov WebGL

Súbor WebGL som umiestnil priamo pod , ale táto metóda ho prepíše, keď umiestnite dva alebo viac súborov WebGL wwwroot . Vysvetlím, ako to dať do samostatných priečinkov a presunúť.

Najprv vytvorte nový priečinok s názvom "webgl" a presuňte ho tam. Dva priečinky, ktoré sa majú Buildpresunúť, sú , TemplateData . index.html Už som ho preniesol na Razor Pages a môžem ho bezpečne odstrániť.

Keďže WebGL.cshtml sme prehĺbili hierarchiu priečinkov, prehĺbime aj cestu opísanú v . Korekcia je 3 riadky.

Pred korekciou

<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
    var buildUrl = "Build";

Po korekcii

<link rel="shortcut icon" href="webgl/TemplateData/favicon.ico">
<link rel="stylesheet" href="webgl/TemplateData/style.css">
    var buildUrl = "webgl/Build";

Spustite program a zistite, či funguje správne.

Spustenie rozhrania WebGL komprimovaného pomocou Gzip

Prípona súboru komprimovaného Gzip je .gz , a je to súbor, ktorý môže spracovať ASP.NET Core, Unity WebGL Content-Type a sú spracované inak a vyžadujú konverziu.

Najprv vytvorte nasadenie súboru WebGL a stránku.

Umiestnenie súboru WebGL

wwwrootwebgl-gzip Vytvorte priečinok pod Gzip a skopírujte priečinok , zo súboru BuildTemplateData WebGL, ktorý ste vytvorili pomocou Gzip.

Vytvorenie stránky s holiacim strojčekom

Tentoraz WebGLGzip.cshtml vytvorte súbor rovnakým postupom ako pri nekomprimovaní.

Kód je nasledovný s odkazom na výstup v index.html jednote. Cesta sa zhoduje s priečinkom, ktorý ste predtým vytvorili webgl-gzip pre súbory WebGL.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLGzipModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <div id="unity-loading-bar">
    <div id="unity-logo"></div>
    <div id="unity-progress-bar-empty">
      <div id="unity-progress-bar-full"></div>
    </div>
  </div>
  <div id="unity-warning"> </div>
  <div id="unity-footer">
    <div id="unity-webgl-logo"></div>
    <div id="unity-fullscreen-button"></div>
    <div id="unity-build-title">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="webgl-gzip/TemplateData/favicon.ico">
  <link rel="stylesheet" href="webgl-gzip/TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    var loadingBar = document.querySelector("#unity-loading-bar");
    var progressBarFull = document.querySelector("#unity-progress-bar-full");
    var fullscreenButton = document.querySelector("#unity-fullscreen-button");
    var warningBanner = document.querySelector("#unity-warning");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == 'warning'の場合、黄色のハイライト色が使用されます。
    // この関数を変更または削除して、重要ではない警告とエラーメッセージがユーザーに表示されるように
    // 視覚的に表示される方法をカスタマイズします。
    function unityShowBanner(msg, type) {
      function updateBannerVisibility() {
        warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
      }
      var div = document.createElement('div');
      div.innerHTML = msg;
      warningBanner.appendChild(div);
      if (type == 'error') div.style = 'background: red; padding: 10px;';
      else {
        if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
        setTimeout(function() {
          warningBanner.removeChild(div);
          updateBannerVisibility();
        }, 5000);
      }
      updateBannerVisibility();
    }

    var buildUrl = "webgl-gzip/Build";
    var loaderUrl = buildUrl + "/WebGL_Gzip.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL_Gzip.data.gz",
      frameworkUrl: buildUrl + "/WebGL_Gzip.framework.js.gz",
      codeUrl: buildUrl + "/WebGL_Gzip.wasm.gz",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Upraviť, ak chcete povoliť navigáciu na Index.cshtml túto stránku.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
  <li><a href="WebGLGzip">WebGLGzip</a></li>
</ul>

Opravný program.cs

app.UseStaticFiles Upravte časť, ktorá spracováva metódu, nasledovne.

Pred korekciou

// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
});
// ここまで追加

Po korekcii

// ここから追加
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".data"] = "application/octet-stream";
provider.Mappings[".wasm"] = "application/wasm";
provider.Mappings[".br"] = "application/octet-stream";   // .br ファイルにアクセスできるように追加
provider.Mappings[".js"] = "application/javascript";     // 後の変換の為に追加

app.UseStaticFiles(new StaticFileOptions()
{
  ContentTypeProvider = provider,
  OnPrepareResponse = context =>
  {
    var path = context.Context.Request.Path.Value;
    var extension = Path.GetExtension(path);

    // 「.gz」「.br」ファイルにアクセスした場合は Content-Type と Content-Encoding を設定する
    if (extension == ".gz" || extension == ".br")
    {
      var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path) ?? "";
      if (provider.TryGetContentType(fileNameWithoutExtension, out string? contentType))
      {
        context.Context.Response.ContentType = contentType;
        context.Context.Response.Headers.Add("Content-Encoding", extension == ".gz" ? "gzip" : "br");
      }
    }
  },
});
// ここまで追加

V ASP.NET Core .gz sa súbor Content-Type application/x-gzip vráti s . Ako to je, Unity WebGL na klientovi to nemôže určiť, takže .gz ho prepíšem a vrátim podľa Content-Type prípony súboru, ktorá vylučuje . Content-Encoding Nastavil som to aj preto, že je to gzip potrebné.

Mimochodom, dal som dohromady aj kód Brotli, takže tento kód môžete použiť tak, ako je to v korešpondencii Brotli ďalšej položky. Brotli tiež .br nastaví prepísanie Content-Encoding br tak, aby zodpovedalo Content-Type prípone súboru bez . Súbor je však predvolene neprístupný v ASP.NET Core,.br takže provider.Mappings som ho pridal pomocou .br .

Potom spustite ladenie a skontrolujte, či hra funguje správne.

Ak ste hru nastavili správne a hra sa stále nezobrazuje, skúste vymazať súbory cookie z vyrovnávacej pamäte webového prehliadača.

Spustenie WebGL komprimovaného pomocou Brotli

Postup je takmer rovnaký ako postup Gzip, pričom časť Gzip sa nahrádza Brotli. Súbory Brotli (.br) však nie sú predvolene prístupné v ASP.NET Core. Musíte ho nakonfigurovať tak, aby ste k nemu mali prístup, ale ak používate kód v čase Gzip, je podporovaný.

Najprv vytvorte nasadenie súboru WebGL a stránku.

Umiestnenie súboru WebGL

wwwrootwebgl-brotli V časti Vytvoriť priečinok skopírujte priečinok , zo súboru WebGL, ktorý BuildTemplateData ste vytvorili pomocou Brotli.

Vytvorenie stránky s holiacim strojčekom

Vytvorte súbor pomocou WebGLBrotli.cshtml rovnakých krokov ako pre Gzip.

Kód je nasledovný s odkazom na výstup v index.html jednote. Cesta sa zhoduje s priečinkom, ktorý ste predtým vytvorili webgl-brotli pre súbory WebGL.

@page
@model UnityPublishWebglAspNetCore.Pages.WebGLBrotliModel
@{
}

<div id="unity-container" class="unity-desktop">
  <canvas id="unity-canvas" width=960 height=600></canvas>
  <div id="unity-loading-bar">
    <div id="unity-logo"></div>
    <div id="unity-progress-bar-empty">
      <div id="unity-progress-bar-full"></div>
    </div>
  </div>
  <div id="unity-warning"> </div>
  <div id="unity-footer">
    <div id="unity-webgl-logo"></div>
    <div id="unity-fullscreen-button"></div>
    <div id="unity-build-title">Platformer</div>
  </div>
</div>

@section Scripts {
  <link rel="shortcut icon" href="webgl-brotli/TemplateData/favicon.ico">
  <link rel="stylesheet" href="webgl-brotli/TemplateData/style.css">
  <script>
    var container = document.querySelector("#unity-container");
    var canvas = document.querySelector("#unity-canvas");
    var loadingBar = document.querySelector("#unity-loading-bar");
    var progressBarFull = document.querySelector("#unity-progress-bar-full");
    var fullscreenButton = document.querySelector("#unity-fullscreen-button");
    var warningBanner = document.querySelector("#unity-warning");

    // 一時的なメッセージバナー/リボンを数秒間表示するか、
    // type == 'error'の場合はキャンバスの上部に永続的なエラーメッセージを表示します。
    // type == 'warning'の場合、黄色のハイライト色が使用されます。
    // この関数を変更または削除して、重要ではない警告とエラーメッセージがユーザーに表示されるように
    // 視覚的に表示される方法をカスタマイズします。
    function unityShowBanner(msg, type) {
      function updateBannerVisibility() {
        warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
      }
      var div = document.createElement('div');
      div.innerHTML = msg;
      warningBanner.appendChild(div);
      if (type == 'error') div.style = 'background: red; padding: 10px;';
      else {
        if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
        setTimeout(function() {
          warningBanner.removeChild(div);
          updateBannerVisibility();
        }, 5000);
      }
      updateBannerVisibility();
    }

    var buildUrl = "webgl-brotli/Build";
    var loaderUrl = buildUrl + "/WebGL_Brotli.loader.js";
    var config = {
      dataUrl: buildUrl + "/WebGL_Brotli.data.br",
      frameworkUrl: buildUrl + "/WebGL_Brotli.framework.js.br",
      codeUrl: buildUrl + "/WebGL_Brotli.wasm.br",
      streamingAssetsUrl: "StreamingAssets",
      companyName: "DefaultCompany",
      productName: "Platformer",
      productVersion: "2.1.0",
      showBanner: unityShowBanner,
    };

    // デフォルトでは、Unity は WebGL キャンバスレンダリングのターゲットサイズを
    // キャンバス要素の DOM サイズ(window.devicePixelRatio でスケーリング)と一致させます。
    // この同期がエンジン内で発生しないようにする場合は、これを false に設定し、
    // 代わりにサイズを大きくします。 キャンバスの DOM サイズと WebGL は、
    // ターゲットサイズを自分でレンダリングします。
    // config.matchWebGLToCanvasSize = false;

    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
      container.className = "unity-mobile";
      // モバイルデバイスでフィルレートのパフォーマンスを低下させないようにし、
      // モバイルブラウザで低 DPI モードをデフォルト/オーバーライドします。
      config.devicePixelRatio = 1;
      unityShowBanner('WebGL builds are not supported on mobile devices.');
    } else {
      canvas.style.width = "960px";
      canvas.style.height = "600px";
    }
    loadingBar.style.display = "block";

    var script = document.createElement("script");
    script.src = loaderUrl;
    script.onload = () => {
      createUnityInstance(canvas, config, (progress) => {
        progressBarFull.style.width = 100 * progress + "%";
      }).then((unityInstance) => {
        loadingBar.style.display = "none";
        fullscreenButton.onclick = () => {
          unityInstance.SetFullscreen(1);
        };
      }).catch((message) => {
        alert(message);
      });
    };
    document.body.appendChild(script);
  </script>
}

Upraviť, ak chcete povoliť navigáciu na Index.cshtml túto stránku.

<!-- 省略 -->

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<!-- 追加 -->
<ul>
  <li><a href="index.html">index.html</a></li>
  <li><a href="WebGL">WebGL</a></li>
  <li><a href="WebGLGzip">WebGLGzip</a></li>
  <li><a href="WebGLBrotli">WebGLBrotli</a></li>
</ul>

Opravný program.cs

Ak ho upravíte, keď je podporovaný Gzip, môžete použiť rovnaký kód.

Po oprave spustite ladenie a skontrolujte, či hra funguje.

Ak ste hru nastavili správne a hra sa stále nezobrazuje, skúste vymazať súbory cookie z vyrovnávacej pamäte webového prehliadača.

Pochopenie príznakov prístupu k súborom Brotli na webovom serveri služby IIS

Brotli nie je štandardne podporovaný IIS, takže je potrebná konfigurácia na strane IIS. Zdá sa, že sa to dá zvládnuť vykonaním pokročilých nastavení, ale v tomto tipe to nebudem vysvetľovať. Pozrite si informácie uvedené nižšie.

Chybové hlásenie

Unable to load file webgl-brotli/Build/WebGL_Brotli.framework.js.br! Check that the file exists on the remote server. (also check browser Console and Devtools Network tab to debug)