Unity – Json Serialization with JsonUtility

The IGL.Common library was originally written to use Json.Net (Popular high-performance JSON framework for .NET).  This works great but makes porting to devices problematic so for Unit this should be replaced with UnityEngine JsonUtility.

For the IGL.Common library this was incredibly simple.  The following lines

public static class JsonSerializerHelper
{
    public static string Serialize(object item)
    {
        if (item != null)
        {
            var serializer = new JavaScriptSerializer();
            return serializer.Serialize(item);
        }
        return null;
    }
 
    public static T Deserialize(string item)
    {
        if (!string.IsNullOrEmpty(item))
        {
            var serializer = new JavaScriptSerializer();
            return serializer.Deserialize(item);
        }
        return default(T);
    }
 
}

were replaced with

public static class JsonSerializerHelper
{
    public static string Serialize(object item)
    {
        if (item != null)
        {
            JsonUtility.ToJson(item);                
        }
        return null;
    }
 
    public static T Deserialize(string item)
    {
        if (!string.IsNullOrEmpty(item))
        {
            JsonUtility.FromJson(item);
        }
        return default(T);
    }
}

Cheers!

Visual Studio Azure Function Template (preview)

Overview

This post provides a simple scenario of using an Azure Function to post messages to Azure Table Storage to illustrate the Visual Studio Azure Function template.
The Azure Table template is available for download here and requires Azure 2.9.6 .NET SDK to be installed.

Note: The template is in preview and does lack some features. Please see the 
announcement
for more details.

Scenario

The scenario does have a couple of interesting points.  First, it uses message definitions from the IndieGamesLab Common NuGet package which illustrates how a NuGet package can be added to a function. Secondly, the Table Storage and Service Bus require configuration to be set and deployed with the project.  Also, the ability to include additional files during deployment is explored.

Adding an Azure Function project to a Solution using the template

After installing the template, the Azure Function (Preview) is available as a new project type in Visual Studio.

8228.2017-01-27_14-27-56.png-550x0

The template generates the project with some default files mirroring what will be deployed in Azure:

6076.2017-01-27_14-29-06.png-550x0

The Project readme provides some insight as to what to do next:

0361.2017-01-27_14-31-53.png-550x0

Adding a New Azure Function to the project

The option New Azure Function… is now available in the Add menu.

2475.2017-01-27_14-47-54.png-550x0

Nice! In Visual Studio now there is a form for creating the Trigger that will start the function.  For this scenario, a new Azure Service Bus trigger will be used. This will start our function when a new queue item is added to the specified queue.

0336.2017-01-27_14-50-42.png-550x0

The run.csx is generated as well the function.json is updated to reflect the new trigger.

{
"disabled": false,
"bindings": [
{
"name": "message",
"type": "serviceBusTrigger",
"direction": "in",
"queueName": "arxevent",
"connection": "indiegameslabbackbone_SB",
"accessRights": "Manage"
}]
}

Application Settings

The appsettings.json file is updated also to include the new settings.

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=...",
    "AzureWebJobsDashboard": "DefaultEndpointsProtocol=https;AccountName=...",
    "indiegameslabbackbone_SB": "Endpoint=sb://indiegameslab.servicebus.windows.net...",
    "indiegameslabbackbone_STORAGE": "DefaultEndpointsProtocol=https;AccountName=..."
  }
}

Referencing Nuget Packages

One great feature of Azure Functions is the simplicity of referencing NuGet packages. This is done in the project.json file. Below shows the references to the required packages:

{
  "frameworks": {
    "net46":{
      "dependencies": {
        "WindowsAzure.Storage": "8.0.1",
        "WindowsAzure.ServiceBus": "3.4.0",
        "Newtonsoft.Json": "4.0.1",
        "IGL.Common": "1.0.5"
      }
    }
  }
}

Implementing the Scenario

In the preview template, intellisense only works with a limited number of libraries (re. System) and not with referenced libraries.  For this scenario, the service bus message is read and parsed as a IGL.GamePacket.  Using the information in the GamePacket,
it is written to table storage.

Note: the assumption here is a message will not come in more frequently than every couple of seconds otherwise there will be a collision on the rowkey.

using IGL;
 
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.ServiceBus.Messaging;
using System.Diagnostics;
using System.Runtime.Serialization;
 
using System;
using System.Threading.Tasks;
 
public static void Run(BrokeredMessage message, ICollector tableBinding, TraceWriter log)
{
    GamePacket packet = null;
 
    try
    {
        log.Info(string.Format("Processing message {0}", message.SequenceNumber));
 
        if (!message.Properties.ContainsKey(GamePacket.VERSION))
            throw new ApplicationException(string.Format("Message {0} does not have a valid {1} property.", message.SequenceNumber, GamePacket.VERSION));
 
        packet = message.GetBody(new DataContractSerializer(typeof(GamePacket)));
 
        tableBinding.Add(new Arx()
        {
            PartitionKey = packet.PlayerId,
            RowKey = packet.PacketCreatedUTCDate.ToString("yyyyMMdd hh:mm:ss"),
            Content = packet.Content
        });
 
        message.Complete();
 
        log.Info(string.Format("Processed message {0} {1} {2}", message.SequenceNumber, packet.PlayerId, packet.PacketCreatedUTCDate.ToString("yyyyMMdd hh:mm:ss")));
    }
    catch (Exception ex)
    {
        message.DeadLetter(ex.Message, ex.GetFullMessage());
 
        log.Error(string.Format("Failed to process {1} with {0}", ex.GetFullMessage(), message.SequenceNumber));
    }
}
 
public class Arx : TableEntity
{
    public string Content { get; set; }   
}

Debugging

Debugging of Azure Functions is supported in Visual Studio as well as attaching to a deployed instance.

Note: the Azure Functions CLI tools will be downloaded when run for the first time.

4861.2017-01-27_14-58-14.png-550x0

Additional Files

One cumbersome task of working with Azure Functions is deploying additional files to Azure that are referenced by the project. This is now relatively trivial. As an example, the following steps were performed to include an XML file to the Azure Function deployment.

  1. A new folder was created in the function folder as shown below:
    7178.2017-02-03_14-21-30.png-550x0
  2. Though there currently is not any support for different file types, an empty file can be added to the folder and renamed as an XML file (e.g.,
    TempInfo.xml).
    4812.2017-02-03_14-39-44.png-550x0
  3.    Simple as that. After a deploy, the file is shown.
    8360.2017-02-03_15-01-34.png-550x0

Summary

As a preview, the Visual Studio Tools for Azure Functions template provides a great step towards creating and managing Azure Functions in Visual Studio.

Issues experienced while creating the wiki

Most of the functionality explored above worked as the announcement stated except for the following:

  • After the deployment to Azure, the NuGet packages were not automatically downloaded. In order to trigger the download, the project.json had to be remotely
    touched to download and re-compile the Function.
  • After the deployment, the Application Settings were not correctly updated and required to be set using the portal.

IGL configuration updated!

IGL.Common was updated to include new configuration.  This is a breaking change and requires the configuration to be changed from:

// set the following once - this is using ACS 
 IGL.Client.Configuration.IssuerName = "IGLGuestClient";
 IGL.Client.Configuration.IssuerSecret = "...";
 IGL.Client.Configuration.ServiceNamespace = "indiegameslab";
 
// optional 
 IGL.Client.Configuration.GameId = 1;
 IGL.Client.Configuration.PlayerId = "TestingTesting";

To:

// set the following once - this is using ACS 
 IGL.Configuration.CommonConfiguration.Instance.BackboneConfiguration.IssuerName = "IGLGuestClient";
 IGL.Configuration.CommonConfiguration.Instance.BackboneConfiguration.IssuerSecret = "...";
 IGL.Configuration.CommonConfiguration.Instance.BackboneConfiguration.ServiceNamespace = "indiegameslab";
 
// optional 
 IGL.Configuration.CommonConfiguration.Instance.GameId = 1;
 IGL.Configuration.CommonConfiguration.Instance.PlayerId = "TestingTesting";

This can also be driven from the web or app configuration files.

IGL.Samples Unity Sample

A new Unity project has been added to IGL.Samples.  The purpose of the project is to illustrate how a Unity game can send messages to and receive messages from the IGL Backbone.

The project contains a scene that has a button to start listening and a button to send a message.  The result of a message is shown in a message box as illustrated below:

unity1

When a message is received, then a message is shown in the console:

unity2

EchoTester

The Canvas object contains a script with the following implementation.

Setting up initial configuration

On the start, some initial configuration is required as well as setting up an event handler for GameEvent messages received and for when errors are encountered in the ServiceBusListener.

Note the settings below are for the IGL Backbone Service and its status can be viewed on the services tab.

void Start () {
 
_instance = Guid.NewGuid();
 
//// initial setup of IGL
 IGL.Client.Configuration.IssuerName = "IGLGuestClient";
 IGL.Client.Configuration.IssuerSecret = "2PenhRgdmlf6F1oNglk9Wra1FRH31pcOwbB3q4X0vDs=";
 IGL.Client.Configuration.ServiceNamespace = "indiegameslab";
 
IGL.Client.Configuration.GameId = 100;
 IGL.Client.Configuration.PlayerId = "TestingTesting";
 
_listener = new IGL.Client.ServiceBusListener();
 
 IGL.Client.ServiceBusListener.OnGameEventReceived += ServiceBusListener_OnGameEventReceived;
 IGL.Client.ServiceBusListener.OnListenError += ServiceBusListener_OnListenError; 
}

Listening for GameEvents

The following show the implementation of the event handlers and both write a message to the console.

private void ServiceBusListener_OnListenError(object sender, System.IO.ErrorEventArgs e)
{
 Debug.LogErrorFormat("Error:{0}", e.GetException().Message);
}
 
private void ServiceBusListener_OnGameEventReceived(object sender, IGL.GamePacketArgs e)
{
 if (e.GamePacket.GameEvent.Properties["Instance"] == null ||
 e.GamePacket.GameEvent.Properties["Instance"] != _instance.ToString())
 return;
 
 var sentTime = DateTime.Parse(e.GamePacket.GameEvent.Properties["Created"]);
 
 Debug.LogFormat("Packet:{0} Round Trip in {1} milliseconds.", 
 e.GamePacket.PacketNumber,
 DateTime.UtcNow.Subtract(sentTime).TotalMilliseconds);
}

The IGL.ServiceBusListener() contains a method that performs an async retrieve from the IGL Backbone for messages addressed to the player.  Though this message is called in Update(), only one request to the Backbone will be sent at a time.

void Update()
{
 if (_listenForMessages == true)
 {
 _listener.ListenForMessages();
 }

Sending a GameEvent

The SendEchoMessage() method is called when the send button is pressed and submits a simple GameEvent to the IGL Backbone:

public void SendEchoMessage()
{ 
 var gameEvent = new IGL.GameEvent
 {
 Properties = new Dictionary<string, string>()
 {
 { "Created", DateTime.UtcNow.ToString() },
 { "Instance", _instance.ToString() }
 }
 };
 
 bool wasSuccessful = IGL.Client.ServiceBusWriter.SubmitGameEvent("Echo", 1, gameEvent);
 
 MessageDisplay.text = "Sent message without error: " + wasSuccessful.ToString() + Environment.NewLine + MessageDisplay.text;
}

 

Echo Function

The Echo Function is live and available for general use while the 1 million free executions lasts!  The status of the Echo Function is on the Echo Function page (Service tab).

As an illustration, the Echo Function will read new messages that are published to the echo queue and publish to the specific player Topic.

func1

Unity AssetServer – FATAL: could not reattach to shared memory

If you run into an issue where the Unity AssetServer fails to start, try a simple restart of the server in the first instance.  There are a heap of posts indicating it is postgres related but I have not gotten to the root of the error.  So far a simple restart of the server seems to clear the shared memory lock but I will be making regular backups as well as at least one person has not been so lucky.

LOG:  database system was interrupted; last known up at 2014-11-12 04:06:49 GMT
LOG:  database system was not properly shut down; automatic recovery in progress
LOG:  record with zero length at 1/F3E78290
LOG:  redo is not required
LOG:  database system is ready to accept connections
FATAL:  could not reattach to shared memory (key=256, addr=018D0000): 487
LOG:  background writer process (PID 2132) exited with exit code 1
LOG:  terminating any other active server processes
FATAL:  could not reattach to shared memory (key=256, addr=018D0000): 487
LOG:  autovacuum launcher started
LOG:  all server processes terminated; reinitializing
FATAL:  pre-existing shared memory block is still in use
HINT:  Check if there are any old server processes still running, and terminate them.

Asset Server on Azure

There are many advantages and disadvantages of using hosted team collaboration services like Visual Studio Online, Git and Subversion compared with the Unity Asset Server.  In some situations, standing up a self-hosted source control repository is a good choice.

Unity Asset Server is only available with a Team License holder.

The following are the steps required to create a Unity Asset Server on the Azure.  Assuming an Azure subscription is already in place, the first step is to provision a new virtual machine.  As we do not require any additional features, a quick create will suffice:

image

The setup is very simple.  A DNS name that has not been currently registered is required and some information about what type of VM.  For my purposes I went with the most inexpensive option with the idea that I could scale up as required (an advantage of using Azure to host the VM).  The user name and password specified here is primarily for remote desktop access to the VM.

image 

Once the server has been fully created, connect to the server from the virtual machine dashboard:

image

Once a connection has been made then install Unity Asset Server.  Before this can be done though the .Net Framework version needs to be updated to include 3.5.  The first step is to start the Server Manager dashboard (at the bottom of the screen):

image

The next step is to enable a new feature:

image

The wizard will take you through several steps.  Most notably are selecting the type of feature-based installation:

image

The particular server needs to be selected:

image

Finally the framework needs to be selected:

image

Once this is complete, then the Asset Server can be installed.  The easiest way is to download the package via the Unity Collaboration page.  The setup is uneventful except for an Asset Server Admin password is required.  This password will be used to create projects and users on the Asset Server from the Unity IDE.

image

The Asset Server should then start and should display that it is running successfully:

image

Now for connectivity to the server remotely.  Back in the Azure Management Portal, the accessible endpoints are listed on the endpoints section of the VM:

image

Click ADD to launch the endpoint wizard.  As this is for a single VM, select the Add a stand-alone endpoint option:

image

On the next page the details of the endpoint are specified:

image

Great.  We are done!  The simplest way to verify the server is listening and available is to use a simple test test.  I used paging as it is free and simple:

image

From here, there are many posts about how to setup the Asset Server including:

Asset Server

Setting up Asset Server with Unity3D over local-network

Debugging Unity with Visual Studio

Congrats to SyntaxTree on being acquired by Microsoft.  I look forward to seeing more innovation in from SyntaxTree and Microsoft in regards to Unity.

You can download the latest tools from the Visual Studio Gallery and install them as normal.

After starting Unity you will see a new Asset available as Visual Studio 2013 Tools:

 image

This will bring in two new dlls into the Unity IDE:

image

If you want to debug your solution in Visual Studio, check the build settings to allow Visual Studio to connect:

image

image

Winner KiwiGameStarter 2014

Great news!  Phantasmal has won the KiwiGameStarter 2014 competition run by the New Zealand Game Developers Association Incorporated (NZGDA).

KiwiGameStarter 2014 is a business start-up competition for New Zealand-based game development teams. Its purpose is to support the commercial success of one high-potential team or project

So what does it mean.  Kudos, a sense of achievement and

  • $10,000 cash
  • One one-year license for Autodesk Maya LT
  • One commercial suite license for Unity 3D
  • public relations and marketing strategy advice from Pursuit Public Relations to the value of $2,000
  • assistance by Hudson Gavin Martin (specialist Technology and IP lawyers) with the drafting of a licence agreement for the winning Entry to license the Winner’s Game to end users (worth $2,000 plus GST) and additional legal advice from Hudson Gavin Martin in relation to the Game up to the value of $2,000 plus GST
  • introductions from the NZGDA to experienced game development professionals in New Zealand (Mentors) who have expertise in a domain or genre relevant to the Winner’s Entry

The pressure is on.  If you haven’t done so, please head over and look at Steam Greenlight: http://steamcommunity.com/sharedfiles/filedetails/?id=291861158&result=1