Unreal Tournament サンプル Web サイト

Unreal Tournament の Web サイトは、サーバーに Node.js を使用し、フロントエンドに jQuery を使用するように最適化しています。型の確認がしやすいように、コード全般に TypeScript を使用しています。

このセクションでは、各コンポーネントを Genvid Web API とリンクさせるコードについてのみ説明します。

サーバーコード

サーバーの記述には Node.js を使用しています。これが、パブリック URL と内部 Genvid サービスの接続を行います。

routes/streams.t.ts ファイル内の経路再選択を指定します。このファイルは、あらかじめ指定したシークレットを使用して、クライアントから disco サービスへのウェブ要求を転送します。

Consul を使用して、URL、disco のシークレット、webgatewayサービスを見つけます。config.ts ファイルは、これらのサービスの検出方法を示しています。

// Copyright 2016-2022 Genvid Technologies LLC. All Rights Reserved.
let envs = require("envs");
import * as Consul from "consul";

let consul_addr = envs("CONSUL_HTTP_ADDR", "127.0.0.1:8500").split(":");
let port = consul_addr.pop();
let host = consul_addr.join(":");
export let consul = Consul({ host: host, port: port });

export let disco_url = envs("GENVID_DISCO_URL", "http://localhost:8080");
export let disco_secret = envs("GENVID_DISCO_SECRET", "discosecret");

export let webgateway_url = envs(
  "GENVID_WEBGATEWAY_URL",
  "http://localhost:8089"
);
export let webgateway_secret = envs(
  "GENVID_WEBGATEWAY_SECRET",
  "webgatewaysecret"
);

export let webEndpointConfig = {
  endpoint: envs("ENDPOINT", undefined),
  secret: envs("CLIENT_SECRET", undefined),
  ssl: envs("SSL", "false")
};

export interface ITaggedAddresses {
  lan: string;
  wan: string;
}

export interface IServiceEntry {
  Node: {
    ID: string;
    Node: string;
    Address: string;
    Datacenter: string;
    TaggedAddresses: ITaggedAddresses;
    Meta: {
      [name: string]: string;
    };
  };
  Service: {
    ID: string;
    Service: string;
    Tags: string[];
    Address: string;
    Meta: {
      [name: string]: string;
    };
    Port: number;
  };
  Checks: {
    Node: string;
    CheckID: string;
    Name: string;
    Status: string;
    Notes: string;
    Output: string;
    ServiceID: string;
    ServiceName: string;
    ServiceTags: string[];
  }[];
}

function wrapIPv6Address(address: string): string {
  if (address.includes(":")) {
    return `[${address}]`;
  }
  return address;
}

function watchService(serviceName: string, setUrl: (url: string) => void) {
  const watchOptions: Consul.Health.ServiceOptions = {
    service: serviceName,
    passing: true
  };

  const serviceWatch = consul.watch({
    method: consul.health.service,
    options: watchOptions
  });

  serviceWatch.on("change", (services: IServiceEntry[], _res) => {
    console.log(services);
    if (services.length === 0) {
      console.error(`${serviceName} service is not available from consul`);
    } else {
      let service = services[Math.floor(Math.random() * services.length)];
      let serviceUrl = `http://${wrapIPv6Address(service.Service.Address)}:${
        service.Service.Port
      }`;
      setUrl(serviceUrl);
      console.info(`Watch ${serviceName} url: ${serviceUrl}`);
    }
  });

  serviceWatch.on("error", err => {
    console.error(`${serviceName} watch error:`, err);
  });
}

watchService("disco", url => {
  disco_url = url;
});
watchService("webgateway", url => {
  webgateway_url = url;
});

サーバーが、2 キーの URL パスのトラフィックを転送します。

このメソッドは、現在のストリームに関する情報を取得します。ブラウザは、このメソッドでストリーム名、説明、チャンネルなどを取得します。

この Web メソッドは、Genvid システムへの接続に使用する URI とトークンを返します。

ブラウザコード

Unreal Tournament Genvid のサンプル Web サイトは次のようになります。

../../_images/ut4_web.png

YouTube からの Unreal Tournament のライブ配信の映像を表示する、シンプルな Web アプリケーションです。プレイヤーを直接選択して、体の周囲に丸いハイライトを表示するビデオオーバーレイが存在します。ビデオの下には、各プレイヤーが視聴者に選択、キル、応援を許可できるコントロールがあります。このコントロールを使って、視聴者は Web ページを通してインタラクとすることができます。

グローバルショートカット

A すべてのプレイヤーを選択、または選択解除
M ストリームのミュート、またはミュート解除
Z ストリームのボリュームを下げる
X ストリームのボリュームを上げる
スペース ストリームの一時停止、または一時停止解除
+ DelayOffset を増やす
- DelayOffset を減らす
* DelayOffset をリセット
F フロアグリッドの表示
G Genvid オーバーレイの表示、または非表示
H ヘルプメニューの表示、または非表示

ビデオ

プレイヤーをクリック プレイヤーを選択 (ビデオに丸いハイライトを付ける)

ヘッダーボタン

Genvid アイコンボタン Genvid オーバーレイの表示、または非表示
? ヘルプメニューの表示、または非表示

ボトムパネル

👍 こプレイヤーのカメラ変更
プレイヤーをキルする
プレイヤーパネル プレイヤーを選択 (ビデオに丸いハイライトを付ける)

Genvid オーバーレイ

Genvid オーバーレイは、YouTube プレイヤーとの交流を回避しながら、各キューブの横に、色付きの円と名前、デバッグ情報を表示します。

Local Web ページを表示するマシンのローカルタイム。
Raw Video ビデオプレイヤーの現在の内部時間。
Est. Video ビデオプレイヤーの予測時間。
Last Compose Compose service からレポートされた直前のデータの時間。
Est. Compose Compose service の予測時間。
ストリーム 一般化されたストリームの現在時刻。
Latency ゲームと視聴者の間の予測遅延時間。
DelayOffset 同期を調整するための遅延オフセット (オプション)

ut4_app.ts

ut4_app.ts ファイルは、プレイヤーのキーボード入力、ビデオプレイヤーコントロール、およびヘルプの処理を行います。

ut4_engage.ts

ut4_engage.ts は Genvid システムを初期化します。

以下の関数は、GenvidClient の初期化方法を示します。ブラウザがストリーム情報を受け取った時に呼び出されます。

private on_channel_join(info: genvid.IChannelJoinResponse) {
    this.client = genvid.createGenvidClient(
        this.streamInfo, info.uri, info.token, this.video_player_id);
    this.client.onVideoPlayerReady((elem) => { this.on_video_player_ready(elem); });
    this.client.onStreamsReceived((streams) => { this.on_streams_received(streams); });
    this.client.onNotificationsReceived(this.on_notifications_received.bind(this));
    this.client.onDraw((frame) => { this.on_new_frame(frame); });
    this.client.start();
}

主な関数には、次のものがあります。

  • onVideoPlayerReady : ビデオプレイヤーの準備ができた時に呼び出されます。
  • onStreamsReceived : ストリーム情報を受け取った時に呼び出されます。
  • onNotificationsReceived : 通知を受け取った時に呼び出されます。
  • onDraw : オーバーレイやコントロールの描画のために、
    毎秒 30 回呼び出されます。

また、このファイルが GenvidClient にイベントを送信します。

public cheer_player(player_name) {
    if (this.client) {
        console.log(`Sending cheer ${player_name}`);
        this.client.sendEventObject({ "cheer": player_name });
    } else {
        console.log("No client connected.");
    }
}

ut4_data.ts

このファイルには、コードで使用されるデータ構造体が含まれています。

ut4_model.ts

ut4_model.ts のファイルは、受信したデータを分析し、使用可能なデータに変換します。

onStreamReceived のメソッドは、ストリームから JSON 情報を解析します。アノテーションの解釈もここで行われます。

// Shows how to parse the JSON inside the streams and annotations
for (let stream of [...streams.streams, ...streams.annotations]) {
    for (let frame of stream.frames) {
        try {
            frame.user = JSON.parse(frame.data);
        }
        catch (err) {
            console.error("Not able to parse JSON: ", err);
        }
    }
}

onNotificationsReceived のメソッドは、通知を解釈します。応援コメント (cheer) は通知を使用して処理されるため、ビデオとの同期よりも、受信タイミングが重要な場合があります。

newGameFrame のメソッドは、ストリーム情報を処理しやすい形式に変換します。

updateGameFrame のメソッドは、フレーム内の情報の分析や更新を行います。このメソッドで、データの表示準備が完了した状態になります。

ut4_gui_playerList.ts

ut4_gui_playerList.ts のファイルは、ビデオの下に表示するコントロールのビューをカプセル化します。また、プレイヤーに重ねて表示するプレイヤーの死亡アイコンを制御します。

PlayerControl の class には、クリックイベントを処理する単一のコントロールが含まれています。

PlayerIndicatorControl の class は、プレイヤーの死亡オーバーレイを制御します。

ut4_gui_infoOverlay.ts

ut4_gui_infoOverlay.ts のファイルには、デバッグ情報のオーバーレイが含まれています。

ut4_webgl.ts

ut4_webgl.ts のファイルは、ビデオ上に WebGL オーバーレイを表示します。オーバーレイには、プレイヤー選択とグリッドが含まれます。視聴者がオーバーレイでプレイヤーをクリックすると、プレイヤーが選択されたかどうかを判断する選択ルーチンが呼び出されます。