Genvid Tutorial Video 2: How to Use the Genvid SDK with Unity

SHARE:

(This is the second in a four-part series; click to jump to posts 1, 3, and 4)

Importing the GenvidTanks Sample Project

The Genvid SDK is compatible with Unity 5.6 and later. In order to run the GenvidTanks Sample you’ll need to make sure that you have Unity 2018.4 installed.

1. Launch the Unity Hub and create a new empty project by clicking the ‘New’ button. When prompted, create the new project in C:/Genvid/GenvidTanksSample. If you’d like to put it somewhere else, make a note of the path because you’ll need it later.

2. Download and import the package from the Unity Asset Store found under Window > Asset Store. In the Asset Store search field, search for “genvidtanks” to locate the package. Follow the instructions to download and import it into your project.

Note that the GenvidTanks Sample uses Unity’s Tanks tutorial project as its base. All of the Genvid specific assets are in the folder: Tanks Content-Modified.

3. Move the Plugins folder from Assets/GenvidTanks to a directory above, but under the Assets directory.

4. Go to Window -> Genvid to open the Genvid Window. This window gives you a summary overview of all of the Genvid dependencies that you have installed, and what projects you have opened. In addition, if you have a working cluster running on your machine, this window will also provide you with an overview and control of the cluster, its settings and current jobs, to complement the Cluster UI, which you can also open from here.

5. Navigate to Assets -> GenvidTanks -> GenvidTanksScene and double-click the file to open the scene.

In the hierarchy, Genvid services and scripts are all packaged under the GenvidSessionManager GameObject, including video and audio streaming and stream command integration with the game client.

6. Uncheck the GenvidSessionManager’s Activate SDK field to Play the game in the editor without the Genvid Services. Check this field again when you want to test with the Genvid Services after you’ve finished configuring them.

7. To enable local controls, go to Edit -> Project Settings -> Input and click on  the preset selector in the top right of the window. Select the Inputs_GenvidTanks file to apply the input settings for the Sample.

How to play the GenvidTanks Sample:

This is a 2 player game where the objective is to defeat the other player. Move player 1 using the W A S D keys and shoot by pressing the Spacebar. Move player 2 with the arrow keys and press enter to shoot.

Audio, Video and Data Streaming

The GenvidSessionManager component is responsible for managing the GenvidSession which initializes and cleans up the GenvidServices. The GenvidSession needs references to the Video, Audio, Data Streaming, Events, and Commands components. These components are attached to child GameObjects of the GenvidSession GameObject. This GameObject must remain persistent throughout the game so that the game can access the Genvid services.

Video

Video is handled by the GenvidVideo component, which is attached to the Video GameObject. It takes a reference to a Camera component via the Video Source field.  You can change the reference to the Camera component in the Video Source if you need to display a different camera to your viewers.

  • Note the different Capture Types:
    • Texture – captures what the assigned camera is rendering without the in-game UI. For a custom viewer experience, it’s best to choose the Texture capture type and implement your own display in the Viewer Web Stream.
    • Automatic – Genvid relies on Windows native graphics API to capture the footage and send it to the services to process. This capture type will capture the UI displayed in Unity, but is limited to whatever the primary camera is that renders your game, thus not allowing you to switch cameras at runtime.

Audio

Audio is handled by the Audio GameObject under the Video GameObject in the Hierarchy. The GenvidAudio component manages how audio is streamed from your game.

  • Note the AudioFormat setting:
    • S16LE – sets the audio format to 16-bit
    • F32LE – sets the audio format to 32-bit.
  • Note the AudioMode setting:
    • Unity – captures audio via the AudioListener attached to the main Camera.
    • WASAPI – captures all audio from the desktop.
    • None – no audio is captured whatsoever.

Data Streams

Data streams are handled by the GenvidStreams component on the Streams GameObject. It allows us to develop and submit custom data to the Genvid Services. This component allows us to submit game data streams, annotations, and notifications to the web stream viewers.

To support more data streams for your own game, you can resize the number of IDs in the GenvidStreams component to add or remove entries.

Framerate – indicates the number of frames skipped between sending data. Framerate being set to 0 for the GameData stream indicates that this data will be sent every frame.  If you were to set the framerate to 20, the game would wait 20 frames between sending updates.

  • Game Data Streams – allows you to send supplemental data such as the game state or which camera is used, but can contain any other type of data. Because this data is meant to represent the state of the game at a specific time and is sent with a timecode, or time stamped data, the web viewer would be able to retrieve the proper game data for each frame between updates.
    • Note the stream with the Id GameData and framerate 0. This stream will send the data every stream.
    • Line 77 in the GenvidTanksGameDataStream.cs sends the data with the following command: Instance.Session.Streams.SubmitGameData (streamId, gameData);
 // SubmitGameData is called every frame and is used to display current stats and to overlay information
    public void SubmitGameData (string streamId) {
        if (GenvidSessionManager.IsInitialized && GenvidSessionManager.Instance.enabled && highRefreshTankData != null && highRefreshTankData.Length > 0) {
            GameData gameData = new GameData () {
                matProjView = mainCam.projectionMatrix * mainCam.worldToCameraMatrix,
                tanks = highRefreshTankData,
                adBillboardMatrix = billboard.transform.localToWorldMatrix,
                lootCountdown = GameManager.Instance.LootDropManager.DropTime - Time.time,
                lootMatrices = ConvertGameObjectListToMatrixArray (GameManager.Instance.LootDropManager.activeLoot),
                explosionMatrices = ConvertGameObjectListToMatrixArray (explosions),
                shellMatrices = ConvertGameObjectListToMatrixArray (shells)
            };
            GenvidSessionManager.Instance.Session.Streams.SubmitGameData (streamId, gameData);
        }
    }
  • Annotations – not all data represents a specific state of the game, even if it may still belong to a specific time in the game. In the GenvidTanksSample, when you defeat an enemy player, the match state changes. When the change is detected, the display is updated to communicate that there is a winner. This type of stream is called an annotation. In this case, the web overlay will not persist the state of this stream. Here, the frame rate is set to 10 as there is no necessity to sync the match state more often than that.
    • Note the stream with the Id MatchState and framerate 10. This is an annotation.
    • Line 106 in the GenvidTanksGameDataStream.cs sends the data with the following command: Instance.Session.Streams.SubmitAnnotation (streamId, matchStateData);
 // SubmitMatchState submits its data as an annotation since it does not change often and because the overlay does not care about
    // persisting the state.  it is submitted less often than gamedata due to only syncing when lastStateID != activeGameState
    int lastStateID = -1;
    public void SubmitMatchState(string streamId) {
        if (GenvidSessionManager.IsInitialized && GenvidSessionManager.Instance.enabled && 
    lastStateID != (int)GameManager.Instance.activeGameState) {
            int winningTankId = GameManager.Instance.RoundWinner == null ? 0 : 
    GameManager.Instance.RoundWinner.m_PlayerNumber;

            lastStateID = (int)GameManager.Instance.activeGameState;

            MatchStateData matchStateData = new MatchStateData () {
                stateID = lastStateID,
                winningTankId = winningTankId,
                roundNumber = GameManager.Instance.RoundNumber,
            };
            GenvidSessionManager.Instance.Session.Streams.SubmitAnnotation (streamId, matchStateData);
        }
    }
  • Notifications – Sometimes however you need to push data to the viewers immediately, with a lower latency than what would be possible with game data or annotations. To do this, the GenvidTanks Sample sends the loot vote data using a notification stream. These streams do not contain timecode data and therefore do not have the same synchronization capability as the other streams. They do however allow for a more responsive web overlay.
    • Note the stream with the Id LootVotesData and framerate 10. This is a notification.
    • Line 122 in the GenvidTanksGameDataStream.cs sends the data with the following command: Instance.Session.Streams.SubmitNotification (streamId, json);
    // with SubmitLootVotesData SubmitNotification is used rather than SubmitGameData because this data needs to get to the web ASAP
    // otherwise any networking delay will make the votes feel unresponsive
    // this is how we work around latencies and it works because it is not tied directly with game state
    string oldVoteJSON;
    public void SubmitLootVotesData (string streamId) {
        if (GenvidSessionManager.IsInitialized && GenvidSessionManager.Instance.enabled && GameManager.Instance.LootDropManager.DropTime != 0) {
            LootVotesData lootData = new LootVotesData () {
                lootVotes = GameManager.Instance.LootDropManager.Votes
            };
            // Get the LootDropData JSON send a notification if it was changed
            var json = JsonUtility.ToJson (lootData);
            if (json != oldVoteJSON) {
                GenvidSessionManager.Instance.Session.Streams.SubmitNotification (streamId, json);
                oldVoteJSON = json;
            }
        }
    }

Events

To create events that viewers can perform, let’s look at the Events GameObject’s GenvidEvents component. This setup is similar to the GenvidStreams component and you can adjust how many events viewers can trigger by resizing the array. If you change the number of events that viewers can trigger, you must also edit the events.json file in the GenvidServices/config directory. Please see the Viewer Web Stream video and Event Filtering documentation for more details.

Since you’re making an interactive stream, you need some way for viewers to interact with the game from the stream they are watching. Right now the GenvidTanks Sample lets viewers cheer for their favorite tank to win by repeatedly clicking on the thumbs up icon.

Currently, events are implemented in the GenvidTanksEvent script and support cheering and loot voting. Each event requires a series of unique IDs so that the event can be triggered from the web stream into your game. These events are flexible, as the majority of the values retrieved are numerical values which can be parsed into your game logic. For more information about event parameters and creating new events please see the Genvid documentation.

>

1. Select the Events GameObject and inspect the GenvidEvents component.

2. Note the 2 events with Ids cheer and dropVote on the GenvidEvents component.

3. These events and the data that they send are also defined in the GenvidServices/config/events.json file.

 {
  "version": "1.7.0",
  "event": {
    "game": {
      "maps": [
        {
          "id": "dropVote",
          "source": "userinput",
          "where": {"key": ["dropVote"], "name": "<dropId>", "type": "number"},
          "key": ["dropVote", "<dropId>"], "value": 1
        },
        {
          "id": "cheer",
          "source": "userinput",
          "where": {"key": ["cheer"], "name": "<tankId>", "type": "number"},
          "key": ["cheer", "<tankId>"], "value": 1
        }
      ],
      "reductions": [
        {
          "id": "dropVote",
          "where": {"key": ["dropVote", "<dropId>"]},
          "key": ["<dropId>"],
          "value": ["$sum"],
          "period": 250
        },
        {
          "id": "cheer",
          "where": {"key": ["cheer", "<tankId>"]},
          "key": ["<tankId>"],
          "value": ["$sum"],
          "period": 250
        }     
      ]
    }
  }
}

4. To implement cheering in Tanks, retrieve each Tank ID and count the number of newly added cheers and add that to the Tank. When selecting loot, you retrieve the loot with the most votes and spawn it into the game world. This is done in the GenvidTanksEvents.cs script.

Commands

The Genvid SDK also offers a solution to provide some viewers with additional administrator privileges.

In the GenvidTanks Sample, admins can power up a particular tank and can restart the game. This is useful if you’re hosting a tournament and want to restart a match remotely during the stream.

1. Click the Commands GameObject and inspect the GenvidCommands component. The setup is similar to that of the previous components  including Streams and Events.

2. The logic for the Tanks game commands live in the GenvidTanksCommands script and are assigned to the GenvidCommands OnCommandTrigger field. For information regarding the Web interface, please take a look at the Viewer Web Stream video.

Continue to the next tutorial ->

Recent Posts