Unity web socket manager plugin for event driven communication with a web socket service


Use Case




Preconditions

The Unity game is built on UWP and .NET standard 2.0.
The Unity game already has been authorized to use the web socket service.

Postconditions

The Unity game can receive messages from the web socket service without sending a request first.

  

Activity flow



Basic flow 1: sending thread.


Step
Description
Software location
1
Unity starts the demo scene.
StupidFun.Games.Unity.CommunicationManager.OnEnable().
2
Unity establishes a connection to the server and starts the sending and listening threads.  For the listening thread, see basic flow 2.
StupidFun.WebSocketManager.Start().
3
The sender thread initializes and begins monitoring the send message queue _sendQueue.
StupidFun.WebSocketManager.StartSender().
4
While the web socket connection is still open:
StupidFun.WebSocketManager.StartSender().
5
Send the message to the web socket service.
StupidFun.WebSocketManager.StartSender().
6
The scene has finished.
StupidFun.Games.Unity.CommunicationManager.OnDisable().

Basic flow 2: listening thread.


Step
Description
Software location
1
While the web socket connection is still open:
StupidFun.WebSocketManager.StartListening().
2
Unity awaits a message from the web socket server.
StupidFun.WebSocketManager.StartListening().
3
Unity receives a message from the web socket server.
StupidFun.WebSocketManager.StartListening().
4
Unity fires an Unity event indicating a message has been received.
StupidFun.Games.Unity.CommunicationManager.TriggerEvent().
5
The message is deserialized into an object and passed to an adapter for game specific processing.  The server assigned session ID is passed to Unity.
StupidFun.Games.Unity.CommunicationManager.OnMessageReceived().
6
The message object is passed to the game specific adapter for processing.
StupidFun.Games.Unity.Adapters.BaseAdapter.Instance.ProcessMessage().
7
Properties in attached child game objects are updated (cannot call any Unity engine APIs).
StupidFun.Games.Unity.Adapters.BaseAdapter.Instance.ProcessMessage().
8
The scene has finished.
StupidFun.Games.Unity.CommunicationManager.OnDisable().

Technical Specifications


The code was written entirely in .NET standard 2.0 for maximum compatibility.
The Unity event handler is instantiated on a different thread than the Unity GUI thread, so when you are passing the message back to the main thread pass it as a string, as in .NET strings are immutable and thread safe.  This makes sure the main thread gets the message.
Do NOT call any Unity APIs in the event thread.  Use the event handler to set properties in other game objects, and wait for the next Update() or FixedUpdate() call to use Unity APIs with the new information.

NOTE: This example does not implement any security model.

Deployment specifications


The top level folder structure:


Of importance is the presence of link.xml file contained within, which has the following contents:

<?xml version="1.0" encoding="utf-8" ?>
<!--
This is a workaround to why DataContractJsonSerializer doesn't work in UWP.
https://issuetracker.unity3d.com/issues/system-dot-configuration-dot-configurationerrorsexception-failed-to-load-configuration-section-for-datacontractserializer
This is to be added to the assets folder of the project.
-->
<linker>
  <assembly fullname="System.Runtime.Serialization" preserve="all"/>
</linker>

This is due to an issue with Unity and details are in this page:

Essentially using .NET standard 2.0 serialization and deserialization libraries won't work without it.








The plugin (StupidFun) folder:



Three assemblies and three debug symbol files were placed in this folder:
StupidFun.Business.Messages.dll contains all the message contracts I created.  There is a copy of this assembly in my server project.
StupidFun.Games.Unity.dll contains all the core functionality, such as StupidFun.CommunicationManager and StupidFun.WebSocketManager classes.
StupidFun.Unity.Samples.dll contains a sample adapter I created for customized handling of web socket messages received in Unity from the server.



Inspector view of assemblies:



The settings should be the same for all three assemblies.  Of importance is under the Windows platform settings, the ScriptingBackend must be set to Il 2 Cpp.  This is necessary for execution on the Universal Windows Platform (UWP).
  

Required Game Objects


Communication Manager




To use the plugin, a game object named CommunicationManager should be created in the scene.  In its inspector view, set the properties as above, except change the Base Url to your own web socket service.  You may wish to increase the Send Queue Limit and Max Received Message values depending on how much information you are expecting to exchange with your server.  The amounts are in bytes.
  

Sample Adapter




The next require game object would be the game adapter, in this case named Sample Adapter.  This adapter can be dragged into the CommunicationManager's Game Adapter properties and vice versa.  You can also create an array of GameObjects as a public property in the adapter, and drag and drop all game components you would like to update upon receiving a message, or just add the game components to be impacted immediately below the adapter game object.  In the ProcessMessage() method of the adapter you can either loop through the array of GameObjects or just through all the child game components of the adapter.  In the case of adding all impacted game components as children of the adapter, it's best to make the adapter the single parent game object of the scene and everything else as a child so the server can impact anything within the scene.

Software Architecture specification


I am just explaining my code and will include key pieces so you can implement your own version.  I highly recommend you make your own plugin.

CommunicationManager


This is just a wrapper game component intended to manage several types of communication, but I have only implemented web sockets.  It requires its own game object in the scene.  This component also contains the event handling and invocation methods, and is implemented as a singleton instance, ensuring it is threadsafe and the only instance possible in the UnityEngine.

Web socket manager


This class implements the sender and listener threads.  In the Start() method it opens a persistent connection to the web socket server, and then starts two threads: a sender and a listener.  Messages meant for the server are first dumped on a queue, and the sender thread reads from the queue and sends off the messages.

The listener thread awaits messages and upon receiving a messages, calls the CommunicationManager.TriggerEvent() to notify the adapter.  This event is spawned on a different thread as well.


StupidFun.Business.Messages.dll

This assembly was built from the source code of the StupidFun.Business.Messages Visual Studio project.  It contains all message contracts used in this demo for communicating between the Unity game (consumer) and the push service.  This assembly is compiled in .NET Standard 2.0 and must exist on both the Unity game and the service application.  It does not require a placeholder assembly in Unity.

StupidFun.Games.Unity.dll


This assembly was built from the source code of the StupidFun.Games.Unity Visual Studio project.  It contains the CommunicationManager and related helper classes, plus some others I was developing.  This assembly is compiled in .NET Standard 2.0 and is only required on the Unity game.  It also does not require a placeholder assembly in Unity.

StupidFun.Unity.Samples.dll


This assembly was built from the source code of the StupidFun.Unity.Samples Visual Studio project.  It contains the SampleAdapter, which contains basic UI code to display the unique identifier returned from the service.  This assembly is compiled in .NET Standard 2.0 and is only required on the Unity game.  It also does not require a placeholder assembly in Unity.



Building the UWP app


Upon selecting the File menu's Build settings subtopic, the pop up dialog contains a button for Player Settings.  Click that so the player settings panel appears, click on the Windows icon on the right hand side, and click on the Other Settings topic.  Under the Configuration section, set the Api compatibility level to .NET Standard 2.0.



Once the UWP solution is built, use Visual Studio to open it and view the project properties for the project named after the Unity project.  In this sample's case, that would be the Sample Event Driven Web Socket project.  Change the platform toolset value to be the version of Visual Studio you are running:




Next deploy the Visual Studio UWP app.  Then run it.  You should see:




If not try restarting the web socket service if it is hosted on Azure.  Azure often shuts down web apps that have not been used for a while.

Note there is a known issue with Unity which means only UWP apps built on 2020.1.0a17 will be able to communicate with web sockets on Xbox One:



Working in the Unity Editor

To provide all the source code, I copied it into a folder WebSocketClientServerSrc in the /Assets/StupidFun folder.  I zipped up the source code into a single archive file so it wouldn’t interfere with the plugin, which was designed to run from the assemblies.


Affiliate link:

Comments

Popular posts from this blog

Sample web socket service for event driven communication