Saturday, September 26, 2015

How to disconnect SmartFox in Unity 5.1.3

Edit - The amazing people at SmartFoxServer let me try a pre-release of client version 1.6.2 which resolves this hang. Keep reading if you want to get some info on how to have a splash screen when your game is closing. You can read the full forum dialog here:
 http://smartfoxserver.com/forums/viewtopic.php?f=20&t=18107

Dear Unity Developers,

I recently updated to Unity5.1.3 and noticed a bad hang on a Windows Standalone Player build when closing my game.

I think that the Disconnect event can no longer be processed in OnApplicationQuit. I have a small workaround. I've reworked my project to load a new scene when the app is closed. I noticed that when my game got disconnected in a normal way (not on quit), it did not hang when I closed it. I researched what could be done, and I found this example in the Unity documentation.

http://docs.unity3d.com/ScriptReference/Application.CancelQuit.html

I'm including my entire SmartFoxManager.cs class. Hopefully this helps people make better use of SmartFox with Unity.

Essentially, what I do now is call Disconnect and then load a closing splash screen that waits for the disconnection (or times out) and calls Application.Quit().
using UnityEngine;
using Sfs2X;
using Sfs2X.Requests;
using Sfs2X.Entities;
using System.Collections;
using Sfs2X.Core;

// Created by Andy Martin

// Statics for holding the connection to the SFS server end
// Can then be queried from the entire game to get the connection

public class SmartFoxManager : MonoBehaviour
{
    public delegate void ConnectionLostDelegate(BaseEvent evt);

    public ConnectionLostDelegate ConnectionLost;

    private static SmartFox smartFox;
    private static SmartFoxManager mInstance;
    public static SmartFoxManager Instance
    {
        get
        {
            if(mInstance == null)
            {
                mInstance = new GameObject("SmartFoxManager").
    AddComponent(typeof(SmartFoxManager)) as SmartFoxManager;
            }

            return mInstance;
        }
    }

    //I have a different class set this connection
    public SmartFox Connection
    {
        get { return smartFox; }
        set 
        { 
            smartFox = value;
            smartFox.AddEventListener(SFSEvent.CONNECTION_LOST, OnConnectionLost);
        }
    }

    private void OnConnectionLost(BaseEvent evt)
    {
        Debug.Log("OnConnectionLost SFSManager");

        if(disconnecting == true)
        {
            disconnecting = false;
            return;
        }

        //Call the event listeners
        if (ConnectionLost != null)
        {
            ConnectionLost(evt);
        }
    }

    public static bool IsInitialized
    {
        get
        {
            return (smartFox != null);
        }
    }

    void Awake()
    {
        DontDestroyOnLoad(this);
    }

    //FixedUpdate is called once per 20 ms
    void Update()
    {
        if (smartFox != null)
        {
            smartFox.ProcessEvents();
        }
    }

    public bool disconnecting = false;
    private bool allowQuitting = false;

    // Handle disconnection automagically
    // ** Important for Windows users - can cause crashes otherwise
    void OnApplicationQuit()
    {
        if (disconnecting == true)
        {
            return;
        }

        Debug.Log("SmartFoxManager OnApplicationQuit");

        if (smartFox != null && smartFox.IsConnected)
        {
            disconnecting = true;

            smartFox.Disconnect();
            StartCoroutine("DelayedQuit");

            if (allowQuitting == false)
            {
                Debug.Log("Cancelled Quit");
                Application.CancelQuit();
            }
        }
        else
        {
            //Quit, you are not connected
            return;
        }

        Debug.Log("End of SmartFoxManager OnAppQuit");
    }

    //Shows an ending splash
    IEnumerator DelayedQuit()
    {
        Debug.Log("Delayed Quit");
        //Take the game out of full-screen mode
        Screen.fullScreen = false;
        Application.LoadLevel("EndSplash");

        int maxTries = 3;
        int tries = 0;
        while (disconnecting == true && ++tries <= maxTries)
        {
            Debug.Log("Hanlding Disconnect");
            yield return new WaitForSeconds(1.0f);
        }

        allowQuitting = true;
        Debug.Log("Allowing Quitting");
        Application.Quit();
    }
}