How to integrate unity3d and Solace pubsub?

Hi I am very happy that I can join to your community.

Since some months ago I was working with solace pub sub+ and now I want to integrate Solace to unity3d for publishing messages from unity to Solace I didn’t have any problem but to receive data from Solace and using unity as a subscriber I had lots of problem and I couldn’t do that.
I would be apricated it if you could help me or connecting me to someone that works with unity and Solace.

@shima, can you provide more info about the problems you’re having so that others can help you?

I want to receive messages from Solace and show it in the unity console. Using
C# / .NET API GitHub - SolaceSamples/solace-samples-dotnet: Getting Started Samples for the Solace .NET API Publish/Subscribe

First I added dll files to unity. Then I make this script and added it to camera.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Text;
using SolaceSystems.Solclient.Messaging;
using System.Threading;
using UnityEngine.UI;
public class Newsub : MonoBehaviour
{
        #region start
        void start()
        {
           Debug.Log("1");
           string host = "localhost";
           string username = "admin";
           string vpnname = "default";
           string password = "admin";

           // Initialize Solace Systems Messaging API with logging to console at Warning level
           ContextFactoryProperties cfp = new ContextFactoryProperties()
           {
               SolClientLogLevel = SolLogLevel.Warning
           };
           cfp.LogToConsoleError();
           ContextFactory.Instance.Init(cfp);

           try
           {
               // Context must be created first
               using (IContext context = ContextFactory.Instance.CreateContext(new ContextProperties(), null))
               {
                   // Create the application
                   using (TopicSubscriber topicSubscriber = new TopicSubscriber()
                   {
                       VPNName = vpnname,
                       UserName = username,
                       Password = password
                   })
                   {
                       // Run the application within the context and against the host
                       topicSubscriber.Run(context, host);
                   }

               }
           }
           catch (Exception ex)
           {
               Console.WriteLine("Exception thrown: {0}", ex.Message);
           }
           finally
           {
               // Dispose Solace Systems Messaging API
               ContextFactory.Instance.Cleanup();
           }
           Console.WriteLine("Finished.");
           Console.WriteLine("message");
           Debug.Log("message");
       }
       #endregion




    /// <summary>
    /// Demonstrates how to use Solace Systems Messaging API for subscribing to a topic and receiving a message
    /// </summary>
    public class TopicSubscriber : IDisposable
    {
        public string VPNName { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }

        public const int DefaultReconnectRetries = 3;

        public ISession Session = null;
        public EventWaitHandle WaitEventWaitHandle = new AutoResetEvent(false);

        public void Run(IContext context, string host)
        {
            // Validate parameters
            if (context == null)
            {
                throw new ArgumentException("Solace Systems API context Router must be not null.", "context");
            }
            if (string.IsNullOrWhiteSpace(host))
            {
                throw new ArgumentException("Solace Messaging Router host name must be non-empty.", "host");
            }
            if (string.IsNullOrWhiteSpace(VPNName))
            {
                throw new InvalidOperationException("VPN name must be non-empty.");
            }
            if (string.IsNullOrWhiteSpace(UserName))
            {
                throw new InvalidOperationException("Client username must be non-empty.");
            }

            // Create session properties
            SessionProperties sessionProps = new SessionProperties()
            {
                Host = host,
                VPNName = VPNName,
                UserName = UserName,
                Password = Password,
                ReconnectRetries = DefaultReconnectRetries
            };

            // Connect to the Solace messaging router
            Console.WriteLine("Connecting as {0}@{1} on {2}...", UserName, VPNName, host);
            // NOTICE HandleMessage as the message event handler
            Session = context.CreateSession(sessionProps, HandleMessage, null);
            ReturnCode returnCode = Session.Connect();
            if (returnCode == ReturnCode.SOLCLIENT_OK)
            {
                Console.WriteLine("Session successfully connected.");

                // This is the topic on Solace messaging router where a message is published
                // Must subscribe to it to receive messages
                Session.Subscribe(ContextFactory.Instance.CreateTopic("tutorial/topic"), true);

                Console.WriteLine("Waiting for a message to be published...");
                WaitEventWaitHandle.WaitOne();
            }
            else
            {
                Console.WriteLine("Error connecting, return code: {0}", returnCode);
            }
        }

        /// <summary>
        /// This event handler is invoked by Solace Systems Messaging API when a message arrives
        /// </summary>
        /// <param name="source"></param>
        /// <param name="args"></param>
        public void HandleMessage(object source, MessageEventArgs args)
        {
            Console.WriteLine("Received published message.");
            // Received a message
            using (IMessage message = args.Message)
            {
                // Expecting the message content as a binary attachment
                Console.WriteLine("Message content: {0}", Encoding.ASCII.GetString(message.BinaryAttachment));
                // finish the program
                WaitEventWaitHandle.Set();
            }
        }

        #region IDisposable Support
        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    if (Session != null)
                    {
                        Session.Dispose();
                    }
                }
                disposedValue = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
        #endregion

        /*#region start
         void start()
         {
            string host = "localhost";
            string username = "admin";
            string vpnname = "default";
            string password = "admin";

            // Initialize Solace Systems Messaging API with logging to console at Warning level
            ContextFactoryProperties cfp = new ContextFactoryProperties()
            {
                SolClientLogLevel = SolLogLevel.Warning
            };
            cfp.LogToConsoleError();
            ContextFactory.Instance.Init(cfp);

            try
            {
                // Context must be created first
                using (IContext context = ContextFactory.Instance.CreateContext(new ContextProperties(), null))
                {
                    // Create the application
                    using (TopicSubscriber topicSubscriber = new TopicSubscriber()
                    {
                        VPNName = vpnname,
                        UserName = username,
                        Password = password
                    })
                    {
                        // Run the application within the context and against the host
                        topicSubscriber.Run(context, host);
                    }

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception thrown: {0}", ex.Message);
            }
            finally
            {
                // Dispose Solace Systems Messaging API
                ContextFactory.Instance.Cleanup();
            }
            Console.WriteLine("Finished.");
            Console.WriteLine("message");
            Debug.Log("message");
        }
        #endregion*/
    }



}

Actually I want to run Topicsubscriber from this link in unity
GitHub - SolaceSamples/solace-samples-dotnet: Getting Started Samples for the Solace .NET API.

I would be appreciate it if you can help me and if you want I can send my unity file.

Hey @shima - what is the error you got when attempting to run your subscriber?

Hey Tamimi, actually first I run your code as a subscriber in visual studio and it works but when I use this code and run it in unity I couldn’t receive anything from my Solace publisher. It doesn’t show anything in console.
I used your Topic publisher code and I could to send message from unity to solace( here Solace was my subscribrer) but I don’t know where is the problem in unity that I couldn’t receive messages in it.

In advance thanks for your help.

Thanks for the details on this Shima. Some important things to look for is

  1. Your connection parameters and
  2. Topics you are publishing/subscribing to

Since your TopicPublisher sample application was able to connect to the Solace Broker, this leaves us with potentially a mismatch topic subscription. It looks like your TopicSubscriber is attempting to subscribe to topic tutorial/topic. How are you testing the subscription process? I am assuming you are running the TopicSubscriber application on unity, and from your Solace Broker management console TryMe tab you are publishing on tutorial/topic correct? Please confirm the setup.

The TopicSubscriber samples has a couple of console writes so are you able to see some logs in the console confirming successful connection to the Solace BrokerConsole.WriteLine("Session successfully connected.");?

Thanks for your information Tamimi.
Actually our team was working with Solace from some months ago also in some questions our team got some helps from you.
As I mentioned I could run your Topicsubscriber code in vs with this topic and this connection parameters with the Solace Broker management console TryMe tab and it works , I think my problem is related to unity if someone works with unity and solace maybe can help me more but I didn’t find anyone in unity community that works with Solace.
In vs I got good results from the GitHub c# samples but in unity in console I didn’t receive any log even I put " Debug.Log(“1”);" in the start function in the fist line but it doesn’t print it in the console if you want I can send my unity file completely.

Hmm interesting. and you mentioned that you did not change any of the TopicSubscriber or TopicPublisher code correct? I’ll keep an eye opened to see if there are any particular unity related caveats you have to take into account.

If you made changes to the files from the samples found on the github repo can you mention what changes you made?

Potentially as well another thing you can confirm on your broker managment console, you can check the connected clients. Run your subscriber in unity and confirm if the client is detected on the broker as a client connection. If you cant find it this means that the connection was not successful

So thanks for your support.
Specifically I want to know that which part of this code is related to start function in unity and which part is related to another options in unity?
In terms of the clients I checked that even when I don’t have any subscriber it shows one subscriber and when I run unity it doesn’t add another subscriber now I don’t understand when I don’t have any subscriber why it shows one as default subscriber?

To run topicpublisher I changed the code like below, this code will send the position of my object to Solace broker.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Text;
using SolaceSystems.Solclient.Messaging;

public class NewBehaviourScript : MonoBehaviour
{
    public float speed;
    public static string position;
   

    public void Update()
    {
        float horizontal = Input.GetAxis("Horizontal") * Time.deltaTime * speed;
        transform.Translate(horizontal, 0, 0);
        Vector3 pos = transform.position;
        position = pos.ToString();

       
        Debug.Log(position);


        string host = "localhost"; // Solace messaging router host name or IP address
        string username = "admin";
        string vpnname = "default";
        string password = "admin";

        // Initialize Solace Systems Messaging API with logging to console at Warning level
        ContextFactoryProperties cfp = new ContextFactoryProperties()
        {
            SolClientLogLevel = SolLogLevel.Warning
        };
        cfp.LogToConsoleError();
        ContextFactory.Instance.Init(cfp);

        try
        {
            // Context must be created first
            using (IContext context = ContextFactory.Instance.CreateContext(new ContextProperties(), null))
            {
                // Create the application
                TopicPublisher topicPublisher = new TopicPublisher()
                {
                    VPNName = vpnname,
                    UserName = username,
                    Password = password
                };

                // Run the application within the context and against the host
                topicPublisher.Run(context, host);

            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception thrown: {0}", ex.Message);
        }
        finally
        {
            // Dispose Solace Systems Messaging API
            ContextFactory.Instance.Cleanup();
        }
        Console.WriteLine("Finished.");
    }



    public class TopicPublisher : NewBehaviourScript
    {
        public string VPNName { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }

        public const int DefaultReconnectRetries = 3;

        

        public void Run(IContext context, string host)
        {
            // Validate parameters
            if (context == null)
            {
                throw new ArgumentException("Solace Systems API context Router must be not null.", "context");
            }
            if (string.IsNullOrWhiteSpace(host))
            {
                throw new ArgumentException("Solace Messaging Router host name must be non-empty.", "host");
            }
            if (string.IsNullOrWhiteSpace(VPNName))
            {
                throw new InvalidOperationException("VPN name must be non-empty.");
            }
            if (string.IsNullOrWhiteSpace(UserName))
            {
                throw new InvalidOperationException("Client username must be non-empty.");
            }

            // Create session properties
            SessionProperties sessionProps = new SessionProperties()
            {
                Host = host,
                VPNName = VPNName,
                UserName = UserName,
                Password = Password,
                ReconnectRetries = DefaultReconnectRetries
            };

            // Connect to the Solace messaging router
            Console.WriteLine("Connecting as {0}@{1} on {2}...", UserName, VPNName, host);
            using (ISession session = context.CreateSession(sessionProps, null, null))
            {
                ReturnCode returnCode = session.Connect();
                if (returnCode == ReturnCode.SOLCLIENT_OK)
                {
                    Console.WriteLine("Session successfully connected.");
                    PublishMessage(session);
                }
                else
                {
                    Console.WriteLine("Error connecting, return code: {0}", returnCode);
                }
            }
        }

        public void PublishMessage(ISession session)
        {
            //position = NewBehaviourScript.position;
            // Create the message
            using (IMessage message = ContextFactory.Instance.CreateMessage())
            {
                message.Destination = ContextFactory.Instance.CreateTopic("tutorial/topic");
                // Create the message content as a binary attachment
                message.BinaryAttachment = Encoding.ASCII.GetBytes(position);

                // Publish the message to the topic on the Solace messaging router
                Console.WriteLine("Publishing message...");
                ReturnCode returnCode = session.Send(message);
                if (returnCode == ReturnCode.SOLCLIENT_OK)
                {
                    Console.WriteLine("Done.");
                }
                else
                {
                    Console.WriteLine("Publishing failed, return code: {0}", returnCode);
                }
            }
        }

        
    }

    // Start is called before the first frame update
    void Start()
    {

        speed = 10f;
    }

    
}

So thats a start, if you dont see a client connection on your broker being added when you start your subscriber on unity, then the issue is with connection.

Do you have your code on a github repo we can take a look at it? Maybe your TopicSubscriber code is not reaching session.Connect(). Try adding some console logs in the following code blocks to better understand the behaviour of your topicSubscriber

            Console.WriteLine("Connecting as {0}@{1} on {2}...", UserName, VPNName, host);
            // NOTICE HandleMessage as the message event handler
            Session = context.CreateSession(sessionProps, HandleMessage, null);
            ReturnCode returnCode = Session.Connect();
            if (returnCode == ReturnCode.SOLCLIENT_OK)
            {
                Console.WriteLine("Session successfully connected.");

                // This is the topic on Solace messaging router where a message is published
                // Must subscribe to it to receive messages
                Session.Subscribe(ContextFactory.Instance.CreateTopic("tutorial/topic"), true);

                Console.WriteLine("Waiting for a message to be published...");
                WaitEventWaitHandle.WaitOne();
            }
            else
            {
                Console.WriteLine("Error connecting, return code: {0}", returnCode);
            }

I got this from here solace-samples-dotnet/src/TopicSubscriber/TopicSubscriber.cs at master · SolaceSamples/solace-samples-dotnet · GitHub.

Regarding this question you had:

In terms of the clients I checked that even when I don’t have any subscriber it shows one subscriber and when I run unity it doesn’t add another subscriber now I don’t understand when I don’t have any subscriber why it shows one as default subscriber?

is it a #client-username client? It might be either a default client or one of your TryMe connections. It might be difficult to tell without having any further information on what youre seeing

And btw, I modified your last comment to include ``` before and after your codeblock for better code formatting in comments :slight_smile:

Thanks for your help based on your suggestions I found the problem.

That’s great. @shima, can you accept the best answer for the benefit of other community members?

Hey @shima - thats great !! Curious to know what was the issue? How were you able to resolve it? it’ll be great to share here in case someone else has the same issue :slight_smile:

Hi Tamimi,
Sorry for my delay in answer,
In the HandleMessage class after receiving the message I changed it to string and with debug.log I showed it in the console.