The Azure Functions emulator can be installed locally on multiple operating systems, allowing you to develop Azure Functions in your own development environment.
In this guide we will be walking through how to install Azure Functions Core Tools version 2.x on Windows. To learn more, visit https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local.
If you are unsure how to verify .NET Framework versions, follow this link.
Download and install .NET 4.7.1 for Windows using this link.
Install the above package here.
***Note: Make sure to install x86.
Download and install the Node.js msi installer under Current Latest Features using this link.
***Note: Make sure to install version 10.x or later.
Download and install Git using this link. Open PowerShell and clone the Pinball Lizard repo by running the following command:
***Note: Set-ExecutionPolicy RemoteSigned might be required.
git clone https://github.com/Azure/gaming.git
Open PowerShell and navigate to the working directory, and then run the following command:
npm install -g azure-functions-core-tools
Download and install VSCode using this link. Search for and download the Azure Functions extension.
Once the extension is installed, click reload and log into your Azure account by clicking on the Azure logo in the Activity bar to show the Azure Functions explorer. Click Sign in to Azure... and follow the instructions.
Now that you have the core utilities installed for Azure Functions, it’s time to launch them. Open PowerShell and then navigate to the web-functions subdirectory in the Pinball Lizard source code you downloaded:
cd <source\_dir>\gaming\\pinball-lizard\\web-functions
Start the Azure Functions host with the following command:
func host start --useHttps
Press CTRL+C to terminate the job.
We will now implement the same logic inside VS Code to ensure that all testing is consistent. In VS Code, open the tasks.json file and edit the command value to match the same command we used earlier.
"command": "func host start",
change to
"command": " func host start --useHttps ",
Press F5 to launch the Functions Host.
***Note: VSCode has known issues with attaching a debugger when using Azure Functions Core tools. You can safely either ignore the message below or disable the debugger.
Press CTRL+C to terminate the job.
Azure Functions uses different methods—bindings and triggers—to access the data it needs. Bindings are input and output pipelines that can access a multitude of data types. Triggers are similar to “calling” the function, and a single payload is required for the trigger to function.
Although there are many types of bindings that can be used, Pinball Lizard used Cosmos DB.
Learn more about Azure Functions triggers and bindings.
***NOTE: The configuration function is the most critical piece of Pinball Lizard. Everything else will fail if this is not functional and in place, either locally or in Azure, before you attempt to start.
All configurations are applied through the Azure portal via Azure Functions Application settings, or through the local Azure Functions settings (<pinball lizard root>\web-functions\local.settings.json).
This function will return all of the configuration parameters required for the Node.js applications. A short description has been included about each configuration.
This guide will walk you through each of these settings step by step so you do not have to worry about filling in the values. The links will point to where in the guide you can find instructions for that paticular value. Values that do not have links will accept the default value listed.
- APP_GATEWAY_IP: [IP ADDRESS]
- IP address of Azure application gateway
- SSL_PASSPHRASE: [STRING]
- Passphrase for SSL cert being used for certs that were generated
- CONFIG_ENDPOINT_URL: [URL]
- Base URL for Azure Functions endpoint (local or Azure)
- CONFIG_ENDPOINT_KEY: [HOST KEY]
- Hashed key that the client is required to send before it will receive any data
- Key that must also be configured through Function App settings in the Azure Functions blade (via the Azure portal, under the Host Keys (All functions) section)
- COMMANDER_IP: [IP ADDRESS]
- IP address given to commander container
- COMMANDER_PORT: [INT]
- Default: 9221
- COMMANDER_TOKEN: [STATIC KEY]
- COMMANDER_NUMBER_OF_FORMATIONS: [INT]
- Default: 12
- Max number of formations that commander will keep at once
- COMMANDER_FORMATION_SIZE: [INT]
- Default: 6
- Max number of Ice Lice per formation
- INTERNAL_RELAY_IP: [IP ADDRESS]
- IP address given to internal relay container
- INTERNAL_RELAY_PORT: [INT]
- Default: 9125
- INTERNAL_RELAY_AUTH_TOKEN: [STATIC KEY]
- INTERNAL_RELAY_ALLOWED_HOSTS: [CSV STRING}
- List of URLs that are allowed to communicate with internal relay (comma separated)
- ROUTER_IP: [IP ADDRESS]
- IP address given to router container
- ROUTER_PORT: [INT]
- Default: 9010
- ROUTER_WS_PORT: [INT]
- Default: 8085
- ROUTER_AUTH_TOKEN: [STATIC KEY]
- MIXER_HANDLER_TOKEN: [STATIC KEY]
- MIXER_HANDLER_IP: [IP ADDRESS]
- IP address given to Mixer container
- MIXER_HANDLER_PORT: [INT]
- Default: 9110
- MIXER_CHANNEL_TOKEN: [STATIC KEY]
- Key obtained from Mixer website on a per-channel basis
- MIXER_CHANNEL_VERSION_ID: [INT]
- Version of Mixer channel being used
- MIXER_BUTTON_COOLDOWN: [INT]
- Default: 5000
- How long button cooldown for interaction should be
- PLAYFAB_HANDLER_IP: [IP ADDRESS]
- IP address given to PlayFab container
- PLAYFAB_HANDLER_PORT: [INT]
- Default: 9111
- PLAYFAB_HANDLER_TOKEN: [STATIC KEY}
- PLAYFAB_API_TITLE_ID: [STATIC KEY]
- Title obtained from PlayFab website
- PLAYFAB_API_SECRET: [STATIC KEY]
- Key obtained from PlayFab website
- ROUTER_FUNCTION_ENDPOINT: [URL]
- Endpoint URL for router function located at <base URL>\api
- ROUTER_FUNCTION_KEY: [STATIC KEY]
- Host key found in Function App settings, part of Azure Functions
When the configuration is changed, config/reload is called, and the app config will be reloaded in memory.
The Function App in Azure requires a default response in order to prevent it from automatically shutting down. We will be creating a simple HTTP trigger function that returns an “ok” response.
Open up the web-functions folder in VS Code and create a new function folder called default.
Within the default folder, first create a function.json file with the following copied and pasted contents:
{
"disabled": false,
"bindings": \[
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": \[
"get"
\]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
\]
}
Then create an index.js file with the following contents within the same default function folder:
'use strict'
/\*
\*
\* Returns a default response. This is required to prevent the Function
App from auto closing
\*
\*/
module.exports = function (context, req) {
context.res = {
body: 'ok'
};
context.done();
}
Press CTRL+K, S to save all changes.
If you do not already have an Azure subscription, you can create one for free at the following link: https://aka.ms/azft-gaming
From your Azure dashboard click the + icon in the top left corner, search the marketplace for Azure Cosmos DB, and click Create.
Name your Cosmos Db instance and select the SQL api. If you do not have an existing resource group, create a new one. Choose your location and click Create when finished.
***Note: Naming will be unique to your environment.
Once you hit save and the Cosmos DB instance is deployed, you will land at the Quick Start page. On the left, navigate to Collections -> Browse -> + Add Database and create a database called VR-Game.
Once you have created the Cosmos DB resource, you will need to record the connection string under the left side navigation to SETTINGS -> Keys -> PRIMARY CONNECTION STRING and input the string into the following two places: Azure Functions App setting (applied in later steps) and the local.settings.json file in the web-functions folder.
AzureWebJobsDocumentDBConnectionString
Create an Azure Storage account by clicking + Create a resource -> Storage -> Storage account.
Name the storage account and select the Location and Resource Group used in previous steps.
Once you have created the storage account, open the newly created account and navigate to SETTINGS -> Access Keys and record the connection string for the following Azure Functions app setting:
"AzureWebJobsStorage":"DefaultEndpointsProtocol=https;AccountName=[name];AccountKey=[key]"
Azure Application Gateway is a web traffic load balancer that enables you to manage traffic to your web applications.
Login to the Azure portal and click + Create a resource found on the upper left-hand corner of the Azure portal. Select Networking and then select Application Gateway.
Enter a name for your gateway and select the resource group you created in previous steps. Make sure to choose the same Location used when creating your resource group and Cosmos DB resource. Select an Instance count of 2.
Create a new virtual network and public IP.
Configure listener to use HTTP, then Review and Create.
Once the Application Gateway has been completely deployed, record the frontend public IP address (gateway IP) and update the following value in the Azure Configuration Function.
- APP_GATEWAY_IP: [IP ADDRESS]
In order to help allocate resources, we will be creating an App Service plan in the Azure Portal.
Click + Create a resource from the top left navigation and then search for or select App Service plan.
Change the OS type to Windows and the location to the same region as your storage account, and then choose your existing resource group.
We will be creating the Function App in the portal and configuring a git CI.
Click + Create a resourse -> Compute -> Function App.
Select Windows OS and App Service, then select the App Service plan you created in the previous steps. Use your existing resource group.
Open up the newly created Function App and navigate to Overview -> Application settings -> General settings. Turn off PHP support and FTP access, as neither are needed, and change platform to 64-bit.
Under Application settings, click + Add new setting and add the application settings found in your web-functions\local.settings.json file. Click Save at the top when done.
***NOTE: The example screenshot does not contain all of the necessary settings.
We will need to update the Endpoint URIs to point to the Azure Function App. Find the Function App URL under <your_function_app> -> Overview URL. It will be in this format: .
Replace localhost:7071 with the above URL for both of the following values in your application settings and local.settings.json.
Note: CONFIG_ENDPOINT_URI ends with <URL>/api.config, and ROUTER_FUNCITON_ENDPOINT ends with <URL>/api as shown in the example below:
CONFIG_ENDPOINT_URI
CONFIG_ENDPOINT_URI":"https://https://pinlizfunctionapp.azurewebsites.net/api/config"
ROUTER_FUNCITON_ENDPOINT
"ROUTER_FUNCTION_ENDPOINT":"https://https://pinlizfunctionapp.azurewebsites.net/api"
HTTP triggers let you use keys for added security. A standard HTTP trigger can use these as an API key, requiring the key to be present on the request. Webhooks can use keys to authorize requests in a variety of ways, depending on what the provider supports.
Host Keys are shared by all functions within the Function App and allow access to any function within the Function App. We will be generating Host Keys for the Router Function and Config Endpoint.
Open the Function App and navigate to Platform Features -> Function app settings -> Host Keys -> Add a new host key. Name the host key but leave the value blank to generate a random key value**. **
Name the Router Function key as follows:
ROUTER_FUNCTION_KEY
Update the corresponding value in both the apps settings of the Function App and within your local.settings.json file with the generated key.
Name the Router Function key as follows:
CONFIG_ENDPOINT_KEY
Update the corresponding value in both the apps settings of the Function App and within your local.settings.json file with the generated key.
Open up the Function App and navigate to Platform features -> CODE DEPLOYMENT -> Deployment options. This action will open right tabs. Then select Setup under Deployments tab. Then Choose Source and select either Git or Github. The following examples will use a local Git repository:
Create a deployment user name and password and click OK when done.
Once you have chosen the source, navigate to General Settings -> Properties.
Record/save the GIT URL in properties for later use.
***Note: If using a local Git repo, you can change the deployment credentials by navigating to CODE DEPLOYMENT -> Deployment credentials.
To generate a random UUID for authentication between containers, use this online UUID generator or one of your choosing. Once you have generated the auth tokens, insert them in your Function App settings and in local.settings.json file for the following values:
"ROUTER_AUTH_TOKEN":
"MIXER_HANDLER_TOKEN"
"INTERNAL_RELAY_AUTH_TOKEN":
"PLAYFAB_HANDLER_TOKEN"
"COMMANDER_TOKEN"
PlayFab is a game-monitoring service that also offers dashboard views for ranking and gameplay statistics. We used PlayFab to monitor the winners at GDC who won prizes for their efforts.
Create a PlayFab account at this link. For this guide, you can create an account with minimal information.
After creating a PlayFab account, add the information below to the Application Settings tab of Azure Functions and to local.settings.json file.
-
PLAYFAB_API_TITLE_ID: ***PLAYFAB API TITLE***
Found under Settings -> API -> Title ID
-
PLAYFAB_API_SECRET: ***PLAYFAB API SECRET***
Found under Settings-> Secret Keys
***Note: The values are required to integrate PlayFab with Pinball Lizard and must be entered into the application settings of Azure Functions.
Mixer is a streaming service that allows the viewer to interact with the person playing the game through various methods. Pinball Lizard uses a single button. We use Mixer in Pinball Lizard by allowing viewers to deploy a radioactive Ice Lice that the player can eat to gain the ability to use the breath weapon.
This is also where we use the microphone built into the Odyssey headset. The player must hold the radioactive Ice Lice near their mouth and make a chewing noise to eat it. Afterwards, if the player makes a loud, roaring noise, it will activate the breath weapon to inflict massive damage.
Create a Mixer Account at this link.
***Note: If you run into issues in Edge, try a different browser.
Create an OAuth client by navigating to MORE -> Developers -> Developer Lab.
Click on the “LET’S CREATE ONE” button as shown in the figure below:
Name the client and input localhost for the Hosts option. Do not select Use Secret Key.
Copy the Client ID to the following URI, which you can navigate to your browser:
https://mixer.com/oauth/authorize?redirect\_uri=https:%2F%2Flocalhost%2Foauth-return&response\_type=token&scope=interactive%3Arobot%3Aself&client\_id=<Client_Id>
The navigation should show 'Page not found.’ Examine the URI you were directed to in order to find your oauth_token. Copy the token part from the URL similar as shown below:
https://localhost/oauth-return#access_token=v6G2g73HAkoKEbuEZqpalkNhEZh8cv8SPUVNN9RaZvRWx7jOg1Bfdioavtxjkv7B&token_type=Bearer&expires_in=31535528&state=
Here is another screen shot from a different URL.
After creating a Mixer account and generating an access token, add the following information to the Application Settings tab of Azure Functions:
-
MIXER_CHANNEL_TOKEN: ***MIXER CHANNEL TOKEN***
- This will be the OAuth token generated in the previous steps.
-
MIXER_CHANNEL_VERSION_ID: ***MIXER CHANNEL VERSION***
To obtain a VERSION ID, first navigate to Developer lab -> MIXPLAY PROJECTS and create a new project.
Next, navigate to the Code tab where you will find the VERSION ID.
Note: The values are required to integrate Mixer with Pinball Lizard and must be entered into the Application settings of Azure Functions and on local.settings.jason file.
We will be creating a separate Git repo for our functions. Open the terminal in VS Code and navigate to <pinball_root>\pinball-lizard\web-functions.
Type the following command to intialize the Git repo:
git init
Type the following command to stage all files:
git add -A
Type the following command to run your initial commit:
git commit -m ‘initial’
Set the remote URL to point to the Azure Functions App using the Git URL recorded in previous steps and the following command:
git remote add azure <git\_url>;
Verify by running the following command:
git remote -v
If you want to use Azure to host serverless functions, you need to publish Azure Functions. This can be verified by checking the portal for populated Azure Functions.
In order to publish your locally developed Azure Functions using Git, enter the Git credentials you created earlier when you run the following command from within the web-functions folder:
git push azure master
Once you have successfully published your Azure Functions, you can verify if your deployment was successful in the Azure portal by navigating to your Function App and expanding Functions.
Learn more about how to publish Azure Functions.
We will be using Postman to verify successful deployment of our functions.
Install Postman using this link.
In order to test the Config function, we will need to add the Router Function key, located in your Function App settings, to the header of the request. Add the following key and value under headers in your GET request:
x-functions-key <ROUTER_FUNCTION_KEY>
Create a GET request pointing to the config URL and click Send.
If successful, it should return the Function configuration with populated values from your application settings.
You can run another test to see if the initialize function is generating an instance ID, which is a requirement of several other functions. By looking at the index.js for the initialize function, you can determine that the function is looking for a player name in the payload, and if one does not exist it will generate one.
In order to test the initialize function, you will need to add the Router Function key to the header of the request and provide a body. Add the following key and value under headers in your POST:
x-functions-key <ROUTER_FUNCTION_KEY>
For the body, select raw and provide empty brackets, as shown below, since the function will generate a random player name.
Ensure your URI is pointing to the initialize function.
e.g. https://<your_function_app_ URI>/api/intialize
Click Send and you should receive a response providing you with an instance ID. Your response should look similar to the following: