예제 #1
0
        /// <summary> Create a new match making request, hosting a match based upon the dropdown menu option </summary>
        private void HostRoom()
        {
            m_hosting = true;
            QuickConnect.m_StaticQuickStart = true; //Not technically true, but prevents QuickConnect from firing upon scene load
            //Gather data for hosting the match
            string matchShortCode = m_MatchShortCodes[m_HostSelectionDropDown.GetComponent <Dropdown>().value];

            m_cleanRoomName = m_RoomNameInputField.GetComponentsInChildren <Text>()[1].text;
            GSRequestData matchData = new GSRequestData();

            matchData.AddString("m_cleanRoomName", m_cleanRoomName);

            //Get max player count
            new LogEventRequest()
            .SetEventKey("GetFoundMatchInfo")
            .SetEventAttribute("MatchShortCode", matchShortCode)
            .Send((_nameResponse) =>
            {
                //Since these calls are asynchronous, call host from inside here
                var matchInfo         = JsonUtility.FromJson <JSONFoundMatchInfoConverter>(_nameResponse.ScriptData.JSON);
                string maxPlayerCount = matchInfo.m_MaxPlayerCount.ToString();
                matchData.AddString("maxPlayerCount", maxPlayerCount);

                //Start hosting the match
                new MatchmakingRequest()
                .SetMatchShortCode(matchShortCode)
                .SetSkill(0)
                .SetMatchData(matchData)
                .Send((_matchMakingResponse) =>
                {
                    if (_matchMakingResponse.HasErrors)
                    {
                        Debug.LogError("GSM| Matchmaking Error\n" + _matchMakingResponse.Errors.JSON);
                        m_HostErrorText.SetActive(true);
                        m_HostErrorText.GetComponent <Text>().text = "Error attempting to host match: \"" + _matchMakingResponse.Errors.JSON + "\"";
                        DisplayPanel(PanelSelection.HostMenu);
                    }
                    else         //Host was successful - update lobby screen
                    {
                        //Add player count and match name to lobby screen
                        m_PlayerCountText.GetComponent <Text>().text = "1/" + matchInfo.m_MaxPlayerCount.ToString();
                        m_MatchNameText.GetComponent <Text>().text   = matchShortCode + ": " + m_cleanRoomName;

                        //Add player name to the player list in the lobby screen
                        m_PlayerListText.GetComponent <Text>().text = m_UsernameInput.GetComponentsInChildren <Text>()[1].text; //Display the users in the room
                        m_ChosenMatch.shortCode = matchShortCode;                                                               //Update matchShortCode in case "host" disconnects
                        GameSparksManager.Instance().SetMatchShortCode(m_ChosenMatch.shortCode);
                    }
                });
            });
        }
 /// <summary>
 /// Send and sets this objects color for the user who called this function and for all other players
 /// </summary>
 /// <param name="_myColor">The color to be set for the user who called this function</param>
 /// <param name="_opponentsColor">The color to be set for everyone who did not call this function (everyone else)</param>
 /// <example><code>
 /// void SomeFunction()
 /// {
 ///     gameobject.GetComponent&lt;ASL.ASLObject&gt;().SendAndSetClaim(() =>
 ///     {
 ///         gameobject.GetComponent&lt;ASL.ASLObject&gt;().SendAndSetObjectColor(new Color(0, 0, 0, 1),  new Color(1, 1, 1, 1));
 ///     });
 /// }
 /// </code></example>
 public void SendAndSetObjectColor(Color _myColor, Color _opponentsColor)
 {
     if (m_Mine)
     {
         transform.GetComponent <Renderer>().material.color = _myColor;
         using (RTData data = RTData.Get())
         {
             data.SetString((int)GameController.DataCode.Id, m_Id);
             data.SetVector4((int)GameController.DataCode.MyColor, _myColor);
             data.SetVector4((int)GameController.DataCode.OpponentColor, _opponentsColor);
             GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.SetObjectColor, GameSparksRT.DeliveryIntent.RELIABLE, data);
         }
     }
 }
예제 #3
0
 /// <summary> Disconnects the user from the specified match </summary>
 /// <param name="_shortCode">the match short code used to determine what match to disconnect from</param>
 /// /// <param name="_matchGroup">The name of the match group this player is a part of</param>
 /// /// <param name="_EndRTSession">Flag indicating whether or not the RT session should be ended with this disconnect</param>
 private void Disconnect(string _shortCode, string _matchGroup, bool _EndRTSession = false)
 {
     new LogEventRequest().SetEventKey("Disconnect").SetEventAttribute("MatchShortCode", _shortCode).
     SetEventAttribute("MatchGroup", _matchGroup).Send((_disconnectResponse) =>
     {
         GameSparksManager.Instance()?.GetRTSession()?.Disconnect();
         if (_EndRTSession)
         {
             //Disconnect from RT Session
             GameSparksManager.Instance().EndRTSession(leaveMatch: true);     //Leave the match as well as disconnect from RT
         }
         m_HostButton.GetComponent <Button>().interactable = true;
         m_FindButton.GetComponent <Button>().interactable = true;
     });
 }
예제 #4
0
 /// <summary>
 /// Takes information gathered from two async functions and uses it to actually send the packet out to all users
 /// informing them that they can begin downloading the Texture2D.
 /// </summary>
 /// <returns></returns>
 public void InformAllUsersTexture2DReadyForDownload()
 {
     m_CurrentlyUploadingTexture2D = false;
     //Send the upload ID to everyone so they can download the correct file
     using (RTData data = RTData.Get())
     {
         data.SetString((int)GameController.DataCode.Id, m_Id);
         data.SetString((int)GameController.DataCode.Texture2DName, m_PostDownloadFunctionInfo[0]);
         data.SetString((int)GameController.DataCode.Texture2DPostDownloadFunctionInfo, m_PostDownloadFunctionInfo[1]);
         data.SetString((int)GameController.DataCode.Texture2DSyncStartFlag, m_PostDownloadFunctionInfo[2]);
         data.SetString((int)GameController.DataCode.Texture2DUploadId, m_UploadIds[0]);
         GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.SendTexture2D, GameSparksRT.DeliveryIntent.RELIABLE, data);
         m_PostDownloadFunctionInfo.RemoveRange(0, 3); //Update list so we don't send repeat data
         m_UploadIds.RemoveAt(0);                      //Update list so we don't send repeat data
         m_Texture2DUploadSizeList.RemoveAt(0);        //Update list so we don't send repeat data
     }
 }
예제 #5
0
        /// <summary>
        /// Connects a user to a game using GameSparks auto-matchmaking ability based upon the room name that the programmer specified in the Unity Editor
        /// for the <see cref="QuickConnect"/> script if they are using <see cref="QuickConnect"/>. Otherwise is moves onto the next step of manually connecting players
        /// </summary>
        private void Connect()
        {
            if (m_QuickConnect && !m_SwitchedToManualMatchMaking)
            {
                GSRequestData matchData = new GSRequestData();
                m_cleanRoomName = Regex.Replace(m_RoomName, @"\s+", "");
                matchData.AddString("m_cleanRoomName", m_cleanRoomName);
                new MatchmakingRequest()
                .SetMatchShortCode("QS") //Quick Start short code
                .SetSkill(1)
                .SetMatchData(matchData)
                .SetMatchGroup(m_cleanRoomName)
                .Send((_matchMakingResponse) =>
                {
                    if (_matchMakingResponse.HasErrors)
                    {
                        Debug.LogError("GSM| Matchmaking Error\n" + _matchMakingResponse.Errors.JSON);
                        m_HostErrorText.SetActive(true);
                        m_HostErrorText.GetComponent <Text>().text = "Error attempting to host match: \"" + _matchMakingResponse.Errors.JSON + "\"";
                        DisplayPanel(PanelSelection.HostMenu);
                    }
                    else //Host was successful - update lobby screen
                    {
                        DisplayPanel(PanelSelection.LobbyScreen);

                        //Add player count and match name to lobby screen
                        m_PlayerCountText.GetComponent <Text>().text = "1/20";
                        m_MatchNameText.GetComponent <Text>().text   = "QS" + ": " + m_RoomName;

                        //Add player name to the player list in the lobby screen
                        m_PlayerListText.GetComponent <Text>().text = m_UsernameInput.GetComponentsInChildren <Text>()[1].text; //Display the users in the room
                        m_ChosenMatch.shortCode = "QS";                                                                         //Update matchShortCode in case "host" disconnects
                        GameSparksManager.Instance().SetMatchShortCode(m_ChosenMatch.shortCode);
                    }
                });
            }
            else
            {
                //Switch to the connection menu
                DisplayPanel(PanelSelection.ConnectionMenu);
                GetMatchShortCodes();
            }
        }
예제 #6
0
        /// <summary>
        /// Attempts to download the image at the specified downloadUrl. Once downloaded, it will transform the byte[] into a Texture2D and
        /// call the user defined function with this texture and the gameobject used to send it as parameters.
        /// </summary>
        /// <param name="downloadUrl">The URL where the image can be downloaded from - given to us by GameSparks</param>
        /// <param name="_aslObject">The object used for sending uploading and/or downloading this image</param>
        /// <param name="_textureName">The name of the texture that was downloaded</param>
        /// <param name="_postDownloadFunctionInfo">The function that will be called after the image is downloaded to
        /// perform whatever operations the user needs to do with the gameobject that is associated with this texture and this texture</param>
        /// <param name="_textureUploadId">The upload id of the image. This is a GameSparks given id.</param>
        /// /// <param name="_syncStart">Flag indicating if once downloaded, if this texture2D should wait until all users have downloaded
        /// before it executes the function it is attached to</param>
        /// <returns>Is a coroutine/IEnumerator, so waits asynchronously until the download is complete or errors</returns>
        private IEnumerator DownloadImage(string downloadUrl, GameObject _aslObject, string _textureName, string _postDownloadFunctionInfo, string _textureUploadId, string _syncStart)
        {
            using (var download = UnityWebRequest.Get(downloadUrl))
            {
                yield return(download.SendWebRequest());

                if (download.isNetworkError || download.isHttpError)
                {
                    print("Download error: " + download.error);
                }
                else //Successful
                {
                    //Inform server we have downloaded this image - once all have downloaded it will delete from the server
                    using (RTData data = RTData.Get())
                    {
                        data.SetString((int)DataCode.Id, _aslObject.GetComponent <ASLObject>().m_Id);
                        data.SetString((int)DataCode.Texture2DUploadId, _textureUploadId);
                        data.SetString((int)DataCode.Texture2DSyncStartFlag, _syncStart);
                        GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.ReadyToDeleteUploadedImageOnServer, GameSparksRT.DeliveryIntent.RELIABLE, data);
                    }

                    //Get Texture2D
                    Texture2D dummyTexture = new Texture2D(1, 1); //Size doesn't matter
                    dummyTexture.LoadImage(download.downloadHandler.data);
                    dummyTexture.name = _textureName;

                    //Call PostDownloadFunction
                    var functionName = Regex.Match(_postDownloadFunctionInfo, @"(\w+)$");
                    functionName.Value.Replace(" ", "");
                    var  className   = Regex.Replace(_postDownloadFunctionInfo, @"\s(\w+)$", "");
                    Type callerClass = Type.GetType(className);
                    _aslObject.GetComponent <ASLObject>()._LocallySetPostDownloadFunction(
                        (ASLObject.PostDownloadFunction)Delegate.CreateDelegate(typeof(ASLObject.PostDownloadFunction), callerClass, functionName.Value), dummyTexture, _textureUploadId);

                    //If syncStart is false, execute right away and remove from list
                    if (_syncStart != "1") //if _syncStart is false
                    {
                        _aslObject.GetComponent <ASLObject>().m_PostDownloadFunction.Invoke(_aslObject.gameObject, dummyTexture);
                        _aslObject.GetComponent <ASLObject>()._LocallyRemovePostDownloadFunction(_aslObject.GetComponent <ASLObject>().m_PostDownloadInfoList.Count - 1);
                    }
                }
            }
        }
예제 #7
0
        IEnumerator LoadScene(string _sceneName)
        {
            yield return(null);

            //Begin to load scene specified
            AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(_sceneName);

            //Don't let the scene activate until all users have it loaded (done via RT server)
            asyncOperation.allowSceneActivation = false;

            //While the scene is loading - output the progress
            while (!asyncOperation.isDone)
            {
                m_LoadingText.text = "\n\nLoading Progress: " + (asyncOperation.progress * 100) + "%";
                //Check if scene is finished loading:
                if (asyncOperation.progress >= 0.9f)
                {
                    if (!m_Loaded)
                    {
                        m_Loaded = true; //Prevent multiple packets from sending unnecessarily

                        //Send packet to RT informing users this player is ready
                        using (RTData data = RTData.Get())
                        {
                            GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.SceneReady, GameSparksRT.DeliveryIntent.RELIABLE, data);
                        }
                    }
                    //Change to text to inform user that they are now waiting on others
                    m_LoadingText.text = "\n\nFinished Loading. Waiting for other players...";
                    if (m_AllPlayersLoaded)
                    {
                        using (RTData data = RTData.Get())
                        {
                            //Send a packet letting all users know this scene is now activated and they can destroy the pending match
                            GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.DestroyPendingMatch, GameSparksRT.DeliveryIntent.RELIABLE, data);
                        }
                        m_AllPlayersLoaded = false;
                        asyncOperation.allowSceneActivation = true;
                    }
                }
                yield return(null);
            }
        }
 /// <summary>
 /// Currently counts down this object's claim time and releases the object back to the relay server after the specified amount of time has passed.
 /// Update is called once per frame
 /// </summary>
 private void Update()
 {
     // If we own it and we have no callbacks to perform
     //Then we don't need to own it anymore and thus can start to cancel it
     if (m_Mine && m_OutstandingClaimCallbackCount == 0 && m_ClaimTime > 0 && m_ClaimTime != 0) //if 0, then hold onto until stolen
     {
         m_ClaimReleaseTimer += Time.deltaTime * 1000;                                          //Translate to milliseconds
         if (m_ClaimReleaseTimer > m_ClaimTime)                                                 //If time to release our claim
         {
             m_ReleaseFunction?.Invoke(gameObject);                                             //If user wants to do something before object is released - let them do so
             _LocallyRemoveReleaseCallback();
             using (RTData data = RTData.Get())
             {
                 data.SetString((int)GameController.DataCode.Id, m_Id);
                 GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.ReleaseClaimToServer, GameSparksRT.DeliveryIntent.RELIABLE, data);
             }
             m_Mine = false; //Release
         }
     }
 }
예제 #9
0
        /// <summary>
        /// Sends a packet out to all players to spawn a prefab object
        /// </summary>
        /// <param name="_prefabName">The name of the prefab to be used</param>
        /// <param name="_position">The position of where the object will be spawned</param>
        /// <param name="_rotation">The rotation orientation of the object upon spawn</param>
        /// <param name="_parentID">The id of the parent object</param>
        /// <param name="_instantiatedGameObjectClassName">The name of the class that contains the user provided function detailing what to do with this object after creation</param>
        /// <param name="_instantiatedGameObjectFunctionName">The name of the user provided function that contains the details of what to do with this object after creation</param>
        /// <param name="_claimRecoveryClassName">The name of the class that contains the user provided function detailing what to do if a claim for this object is rejected</param>
        /// <param name="_claimRecoveryFunctionName">The name of the user provided function that contains the details of what to do with this object if a claim for it is rejected</param>
        /// <param name="_sendFloatClassName">The name of the class that contains the user provided function detailing what to do when a user calls <see cref="ASLObject.SendFloats(float[])"/></param>
        /// <param name="_sendFloatFunctionName">The name of the user provided function that contains the details of what to do with this object if a user calls <see cref="ASLObject.SendFloats(float[])"/></param>
        private static void SendSpawnPrefab(string _prefabName, Vector3 _position, Quaternion _rotation, string _parentID = "", string _instantiatedGameObjectClassName = "", string _instantiatedGameObjectFunctionName = "",
                                            string _claimRecoveryClassName = "", string _claimRecoveryFunctionName = "", string _sendFloatClassName = "", string _sendFloatFunctionName = "")
        {
            string guid = Guid.NewGuid().ToString();

            using (RTData data = RTData.Get())
            {
                data.SetString((int)GameController.DataCode.Id, guid);
                data.SetString((int)GameController.DataCode.PrefabName, _prefabName);
                data.SetVector3((int)GameController.DataCode.LocalPosition, _position);
                data.SetVector4((int)GameController.DataCode.LocalRotation, new Vector4(_rotation.x, _rotation.y, _rotation.z, _rotation.w));
                data.SetString((int)GameController.DataCode.ParentId, _parentID);
                data.SetString((int)GameController.DataCode.InstantiatedGameObjectClassName, _instantiatedGameObjectClassName);
                data.SetString((int)GameController.DataCode.InstantiatedGameObjectFunctionName, _instantiatedGameObjectFunctionName);
                data.SetString((int)GameController.DataCode.ClaimRecoveryClassName, _claimRecoveryClassName);
                data.SetString((int)GameController.DataCode.ClaimRecoveryFunctionName, _claimRecoveryFunctionName);
                data.SetString((int)GameController.DataCode.SendFloatClassName, _sendFloatClassName);
                data.SetString((int)GameController.DataCode.SendFloatFunctionName, _sendFloatFunctionName);
                GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.SpawnPrefab, GameSparksRT.DeliveryIntent.RELIABLE, data);
            }
        }
예제 #10
0
 /// <summary>
 /// Send and set the local scale for this object for all users
 /// </summary>
 /// <param name="_localScale">The new local scale for this object</param>
 /// <example><code>
 /// void SomeFunction()
 /// {
 ///     gameobject.GetComponent&lt;ASL.ASLObject&gt;().SendAndSetClaim(() =>
 ///     {
 ///         gameobject.GetComponent&lt;ASL.ASLObject&gt;().SendAndSetLocalScale(new Vector3(.5, 2, .5));
 ///     });
 /// }
 /// </code></example>
 public void SendAndSetLocalScale(Vector3?_localScale)
 {
     if (_localScale.HasValue)
     {
         using (RTData data = RTData.Get())
         {
             data.SetString((int)GameController.DataCode.Id, m_Id);
             data.SetVector3((int)GameController.DataCode.LocalScale, new Vector3(_localScale.Value.x, _localScale.Value.y, _localScale.Value.z));
             GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.LocalScaleUpdate, GameSparksRT.DeliveryIntent.RELIABLE, data);
         }
     }
     else //Send my position as is, not a new position as there was no new position passed in.
     {
         using (RTData data = RTData.Get())
         {
             data.SetString((int)GameController.DataCode.Id, m_Id);
             data.SetVector3((int)GameController.DataCode.LocalScale, new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z));
             GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.LocalScaleUpdate, GameSparksRT.DeliveryIntent.RELIABLE, data);
         }
     }
 }
        /// <summary>
        /// Find all ASL Objects in the scene and have the relay server create a unique ID for them as well as add this object to our ASLObject dictionary
        /// This function is triggered when this script is first loaded
        /// </summary>
        private void SyncronizeID()
        {
            ASLObject[] m_StartingASLObjects = FindObjectsOfType(typeof(ASLObject)) as ASLObject[];
            int         startingObjectCount  = 0;

            foreach (ASLObject _ASLObject in m_StartingASLObjects)
            {
                if (_ASLObject.m_Id == string.Empty || _ASLObject.m_Id == null) //If object does not have an ID
                {
                    using (RTData data = RTData.Get())
                    {
                        //Have the RT server create an ID and send it back to everyone
                        GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.ServerSetId, GameSparksRT.DeliveryIntent.RELIABLE, data);

                        //Add the starting objects to our dictionary without a key. Key will be added later to ensure all clients have the same key
                        ASLHelper.m_ASLObjects.Add(startingObjectCount.ToString(), _ASLObject);
                    }
                    startingObjectCount++;
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Triggers when a match is found either through hosting or through selecting a match. Sets the lobby screen variables
        /// </summary>
        /// <param name="_message">The message from the GameSparks API</param>
        private void OnMatchUpdate(GameSparks.Api.Messages.MatchUpdatedMessage _message)
        {
            if (m_GameStarted)
            {
                return;
            }                                            //No need to update lobby screen if game is started
            m_TempRTSessionInfo.GetPlayerList().Clear(); //Clear player list so we can ensure it is correctly updated
            //Add player name to the player list
            StringBuilder playerList = new StringBuilder();

            foreach (GameSparks.Api.Messages.MatchUpdatedMessage._Participant player in _message.Participants)
            {
                playerList.AppendLine(player.DisplayName); //Add the player number and display name to the list
                if (!GameSparksManager.m_PlayerIds.ContainsKey(player.Id))
                {
                    GameSparksManager.m_PlayerIds.Add(player.Id, false);
                }
                Debug.Log("Updating player list");
                m_TempRTSessionInfo.GetPlayerList().Add(new RTPlayer(player.DisplayName, player.Id, (int)player.PeerId));
            }
            m_PlayerCountText.GetComponent <Text>().text       = _message.Participants.Count() + "/" + m_MaxPlayerCount;
            m_PlayerListText.GetComponent <Text>().text        = playerList.ToString(); //Display the users in the room
            m_ReadyButton.GetComponent <Button>().interactable = true;                  //Allow user to ready up


            //If a player left the match, restart the ready up process
            if (_message?.RemovedPlayers?.Count > 0)
            {
                //If connected to RT session, disconnect
                GameSparksManager.Instance().EndRTSession();
                //Remove player from our player list
                foreach (var player in _message.RemovedPlayers)
                {
                    if (GameSparksManager.m_PlayerIds.ContainsKey(player))
                    {
                        GameSparksManager.m_PlayerIds.Remove(player);
                    }
                }
            }
        }
예제 #13
0
 /// <summary> Requests to join the selected match</summary>
 private void JoinMatch()
 {
     QuickConnect.m_StaticQuickStart = true; //Not technically true, but prevents QuickConnect from firing upon scene load
     //Since we disconnected from our matches, reconnect to match making
     new MatchmakingRequest()
     .SetMatchShortCode(m_ChosenMatch.shortCode)
     .SetSkill(0)
     .Send((_matchMakingResponse) =>
     {
         if (_matchMakingResponse.HasErrors)
         {
             Debug.LogError("GSM| Matchmaking Error\n" + _matchMakingResponse.Errors.JSON);
             m_SearchMatchErrorText.SetActive(true);
             m_SearchMatchErrorText.GetComponent <Text>().text = "Error attempting to join match making: \"" + _matchMakingResponse.Errors.JSON + "\"";
         }
         else
         {
             //Join the match we wanted to join now that we're back in match making
             m_hosting = true;     //Not really hosting, but ready to join a match
             new JoinPendingMatchRequest()
             .SetMatchShortCode(m_ChosenMatch.shortCode)
             .SetPendingMatchId(m_ChosenMatch.id)
             .Send((_JoinPendingMatchResponse) =>
             {
                 if (_JoinPendingMatchResponse.HasErrors)
                 {
                     Debug.LogError("GSM| Finding match Error\n" + _JoinPendingMatchResponse.Errors.JSON);
                     m_JoinMatchErrorText.SetActive(true);
                     m_JoinMatchErrorText.GetComponent <Text>().text = "Error attempting to join match: \"" + _JoinPendingMatchResponse.Errors.JSON + "\"";
                 }
                 else
                 {
                     GameSparksManager.Instance().SetMatchShortCode(m_ChosenMatch.shortCode);
                 }
             });
         }
     });
 }
 /// <summary>
 /// Unity function that is ran right when this class is first initialized (before Start())
 /// </summary>
 private void Awake()
 {
     m_Instance = this;
     DontDestroyOnLoad(gameObject); //Since this holds our network information, we make sure it won't get deleted between scene loads
 }
예제 #15
0
        /// <summary>
        /// Triggers when a match is found either through hosting or through selecting a match. Sets the lobby screen variables
        /// </summary>
        /// <param name="_message">The message from the GameSparks API</param>
        private void OnMatchFound(GameSparks.Api.Messages.MatchFoundMessage _message)
        {
            //If we don't have ourselves as an ID yet, then we can't find a match (though from a GameSparks perspective we can)
            if (!GameSparksManager.m_PlayerIds.ContainsValue(true))
            {
                return;
            }

            //Get matchGroup
            string matchGroup = _message.MatchGroup;

            if (string.IsNullOrEmpty(matchGroup))
            {
                matchGroup = "";
            }
            GameSparksManager.Instance().SetMatchGroup(matchGroup);

            //Don't transition to the lobby screen if just looking for a match
            if (!m_hosting && (!m_QuickConnect || m_SwitchedToManualMatchMaking))
            {
                m_JoinMatchButton.GetComponent <Button>().interactable = false;
                m_JoinMatchButtonInteractable = false;
                //Disconnect from match instance so we can join the match we want to join (since we're looking at matches)
                new LogEventRequest().SetEventKey("Disconnect").SetEventAttribute("MatchShortCode", _message.MatchShortCode).
                SetEventAttribute("MatchGroup", matchGroup).Send((_disconnectResponse) =>
                {
                    m_JoinMatchButtonInteractable = true;
                    foreach (GameObject _potentialMatch in GameObject.FindGameObjectsWithTag("PotentialMatchButton"))
                    {
                        _potentialMatch.GetComponent <Button>().interactable = true;
                    }
                    m_SearchMatchErrorText.GetComponent <Text>().text = "";
                    m_SearchMatchErrorText.SetActive(false);
                });

                return;
            }

            DisplayPanel(PanelSelection.LobbyScreen);
            GameSparksManager.Instance().m_MyMatchId = _message.MatchId;
            m_TempRTSessionInfo = new RTSessionInfo(_message); // we'll store the match data until we need to create an RT session instance

            //Trigger Cloud event to gather max player count for this match and also grab the match name, placing these variables on the lobby screen.
            new LogEventRequest()
            .SetEventKey("GetFoundMatchInfo")
            .SetEventAttribute("MatchShortCode", _message.MatchShortCode)
            .Send((_nameResponse) =>
            {
                var matchInfo = JsonUtility.FromJson <JSONFoundMatchInfoConverter>(_nameResponse.ScriptData.JSON);
                StringBuilder matchDetails = new StringBuilder();
                m_MaxPlayerCount           = matchInfo.m_MaxPlayerCount.ToString();
                m_PlayerCountText.GetComponent <Text>().text       = _message.Participants.Count() + "/" + m_MaxPlayerCount;
                m_MatchNameText.GetComponent <Text>().text         = _message.MatchShortCode + ": " + _message.MatchData.GetString("m_cleanRoomName");
                m_ReadyButton.GetComponent <Button>().interactable = true;    //Allow user to ready up
            });

            //Add player name to the player list
            StringBuilder playerList = new StringBuilder();

            foreach (GameSparks.Api.Messages.MatchFoundMessage._Participant player in _message.Participants)
            {
                playerList.AppendLine(player.DisplayName); //Add the player number and display name to the list
                if (!GameSparksManager.m_PlayerIds.ContainsKey(player.Id))
                {
                    GameSparksManager.m_PlayerIds.Add(player.Id, false);
                }
            }
            m_PlayerListText.GetComponent <Text>().text = playerList.ToString(); //Display the users in the room
        }
예제 #16
0
        /// <summary>Start is called before the first frame update</summary>
        void Start()
        {
            #region Initialize needed UI elements

            m_InfoTextPanel        = GameObject.Find("InfoTextPanel");
            m_UserNameText         = GameObject.Find("UsernameText");
            m_ConnectionStatusText = GameObject.Find("ConnectionStatusText");

            m_MainMenuPanel  = GameObject.Find("MainMenuPanel");
            m_UsernameInput  = GameObject.Find("UsernameInputField");
            m_ConnectButton  = GameObject.Find("ConnectButton");
            m_LoginErrorText = GameObject.Find("LoginErrorText");

            m_ConnectionMenuPanel = GameObject.Find("ConnectionMenuPanel");
            m_HostButton          = GameObject.Find("HostSessionButton");
            m_FindButton          = GameObject.Find("FindSessionButton");

            m_HostMenuPanel         = GameObject.Find("HostMenuPanel");
            m_HostSelectionDropDown = GameObject.Find("MatchNamesDropDown");
            m_RoomNameInputField    = GameObject.Find("RoomNameInputField");
            m_StartHostingButton    = GameObject.Find("StartHostingButton");
            m_HostErrorText         = GameObject.Find("HostErrorText");

            m_RoomViewPanel        = GameObject.Find("RoomViewPanel");
            m_RefreshButton        = GameObject.Find("RefreshButton");
            m_JoinMatchButton      = GameObject.Find("JoinMatchButton");
            m_SearchMatchErrorText = GameObject.Find("SearchMatchErrorText");
            m_JoinMatchErrorText   = GameObject.Find("JoinMatchErrorText");

            m_LobbyScreen     = GameObject.Find("LobbyScreenPanel");
            m_MatchNameText   = GameObject.Find("MatchNameText");
            m_PlayerCountText = GameObject.Find("PlayerCountText");
            m_PlayerListText  = GameObject.Find("PlayerListText");
            m_ReadyButton     = GameObject.Find("ReadyButton");

            m_SetupPanel = GameObject.Find("SetupPanel");

            m_BackButton = GameObject.Find("BackButton");

            m_MatchButtonPrefab = (GameObject)Resources.Load("ASL_Prefabs/AvailableMatchButtons", typeof(GameObject));

            #endregion

            #region Debug.Assert statements
            Debug.Assert(m_InfoTextPanel != null, "The Info Text Panel was null - attach it to this script");
            Debug.Assert(m_MainMenuPanel != null, "The Main Menu Panel was null - attach it to this script");
            Debug.Assert(m_ConnectionMenuPanel != null, "The Connection Menu Panel was null - attach it to this script");
            Debug.Assert(m_HostMenuPanel != null, "Info Host Menu Panel was null - attach it to this script");
            Debug.Assert(m_RoomViewPanel != null, "Info Room View Panel was null - attach it to this script");
            Debug.Assert(m_UserNameText != null, "Username text object under the Info Text Panel was null - attach it to this script");
            Debug.Assert(m_ConnectionStatusText != null, "Connection Status text object under the Info Text Panel was null - attach it to this script");
            Debug.Assert(m_UsernameInput != null, "Username Input Field under the Main Menu Panel was null - attach it to this script");
            Debug.Assert(m_ConnectButton != null, "Connect button under the Main Menu Panel was null - attach it to this script");
            Debug.Assert(m_HostButton != null, "Host Session button under the Connection Menu Panel was null - attach it to this script");
            Debug.Assert(m_FindButton != null, "Find button under the Connection Menu Panel was null - attach it to this script");
            Debug.Assert(m_HostSelectionDropDown != null, "Host dropdown selection under the Host Menu Panel was null - attach it to this script");
            Debug.Assert(m_StartHostingButton != null, "Start hosting button under the Host Menu Panel was null - attach it to this script");
            Debug.Assert(m_LobbyScreen != null, "The Lobby Screen panel was null - attach it to this script");
            Debug.Assert(m_ReadyButton != null, "Ready button under the Lobby Screen panel was null - attach it to this script");
            Debug.Assert(m_PlayerListText != null, "Players text under PlayerHolder in Lobby Screen panel was null - attach it to this script");
            Debug.Assert(m_PlayerCountText != null, "Player Count text under MatchDetails in Lobby Screen panel was null - attach it to this script");
            Debug.Assert(m_MatchNameText != null, "Match Name text under MatchDetails in Lobby Screen panel was null - attach it to this script");
            Debug.Assert(m_HostErrorText != null, "Host Error Text text in Host Menu panel was null - attach it to this script");
            Debug.Assert(m_SearchMatchErrorText != null, "Search Match Text text in Room Find panel was null - attach it to this script");
            Debug.Assert(m_BackButton != null, "Back button was null - attach it to this script");
            Debug.Assert(m_RefreshButton != null, "Refresh button in Room View panel was null - attach it to this script");
            Debug.Assert(m_JoinMatchButton != null, "Join button in Room View panel was null - attach it to this script");
            Debug.Assert(m_MatchButtonPrefab != null, "Join button in Room View panel was null - attach it to this script");
            Debug.Assert(m_RoomNameInputField != null, "User Defined Room Name Input Field in the Host Menu panel was null - attach it to this script");
            Debug.Assert(m_JoinMatchErrorText != null, "Join Match Error text in the Room View panel was null - attach it to this script");
            Debug.Assert(m_LoginErrorText != null, "Login Error text in the Main Menu Panel was null - attach it to this script");

            #endregion

            //Set match button to starting position - will increment whenever we add a new match
            m_OldMatchButtonPosition = m_MatchButtonPrefab.transform.localPosition;
            m_QuickConnect           = QuickConnect.m_StaticQuickStart;
            m_RoomName = QuickConnect.m_StaticRoomName;
            m_ConnectionStatusText.GetComponent <Text>().text = "No Connection..."; //Let the user know they aren't connected yet.
            m_SearchMatchErrorText.SetActive(false);
            m_HostErrorText.SetActive(false);
            m_JoinMatchErrorText.SetActive(false);
            m_ReadyButton.GetComponent <Button>().interactable = false;
            //Set Main Menu to be the current panel showing
            DisplayPanel(PanelSelection.MainMenu);
            m_StaticStartingScene = m_StartingScene;
            m_ConnectButton.GetComponent <Button>().interactable   = false;
            m_JoinMatchButton.GetComponent <Button>().interactable = false;
            m_HostButton.GetComponent <Button>().interactable      = false;
            m_FindButton.GetComponent <Button>().interactable      = false;
            //Button Click Listeners
            #region GUI Listeners

            m_BackButton.GetComponent <Button>().onClick.AddListener(() =>
            {
                m_HostButton.GetComponent <Button>().interactable      = false;
                m_FindButton.GetComponent <Button>().interactable      = false;
                m_JoinMatchButton.GetComponent <Button>().interactable = false;
                m_JoinMatchButtonInteractable = false;
                //Disconnect from anything we may be connected to via the lobby screen (just 1 match)
                if (m_LobbyScreen.activeSelf)
                {
                    if (m_ChosenMatch.shortCode == "QS")
                    {
                        Disconnect(m_ChosenMatch.shortCode, m_cleanRoomName, true);
                    }
                    else
                    {
                        Disconnect(m_ChosenMatch.shortCode, "", true);
                    }
                }
                //Disconnect from pending matches we created (this will destroy the match as we are the only ones in them)
                if (m_RoomViewPanel.activeSelf)
                {
                    foreach (string match in m_MatchShortCodes)
                    {
                        Disconnect(match, "");
                    }
                }
                DisplayPanel(PanelSelection.ConnectionMenu);
                if (m_MatchShortCodes == null || m_MatchShortCodes?.Count == 0) //If we haven't generated short codes yet
                {
                    GetMatchShortCodes();
                }
                m_SwitchedToManualMatchMaking = true;
            });

            m_ConnectButton.GetComponent <Button>().onClick.AddListener(() =>
            {
                // string.empty is passed in for a password because we don't require users have to a password but the GameSparks API does
                GameSparksManager.Instance().AuthenticateUser(m_UsernameInput.GetComponentsInChildren <Text>()[1].text, string.Empty, OnRegistration, OnAuthentication);
                m_LoginErrorText.GetComponent <Text>().text = string.Empty;
            });

            m_HostButton.GetComponent <Button>().onClick.AddListener(() =>
            {
                m_StartHostingButton.GetComponent <Button>().interactable = false;
                //Bring up the Host Menu Panel
                DisplayPanel(PanelSelection.HostMenu);
                SetupHostDropDownMatchOptions();
            });

            m_StartHostingButton.GetComponent <Button>().onClick.AddListener(() =>
            {
                //Setting up match screen:
                DisplayPanel(PanelSelection.Setup);
                //Start the match making process
                HostRoom();
            });

            m_FindButton.GetComponent <Button>().onClick.AddListener(() =>
            {
                //Bring up the Room Find Panel
                DisplayPanel(PanelSelection.RoomView);
                //Search for rooms
                SearchForHostedRooms();
            });

            m_JoinMatchButton.GetComponent <Button>().onClick.AddListener(() =>
            {
                //Join the selected match
                JoinMatch();
            });

            //This is a listener for the Ready Button. On click, we will pass the stored RTSessionInfo to the GameSparksManager to create a new RT session
            m_ReadyButton.GetComponent <Button>().onClick.AddListener(() =>
            {
                GameSparksManager.Instance().StartNewRTSession(m_TempRTSessionInfo);
            });

            //Search for rooms again
            m_RefreshButton.GetComponent <Button>().onClick.AddListener(() =>
            {
                m_JoinMatchErrorText.SetActive(false);
                m_SearchMatchErrorText.SetActive(false);
                SearchForHostedRooms();
            });

            #endregion

            #region GameSpark API Listeners
            //This listener will update the text in the match details field if no match was found
            GameSparks.Api.Messages.MatchNotFoundMessage.Listener = (message) =>
            {
                m_HostErrorText.SetActive(true);
                m_HostErrorText.GetComponent <Text>().text = "Failed to host match: \"" + message.JSONString + "\"";
                m_BackButton.gameObject.SetActive(true);
                DisplayPanel(PanelSelection.HostMenu);
            };

            //This listener will inform players they found a match
            GameSparks.Api.Messages.MatchFoundMessage.Listener += OnMatchFound;
            //This listener will inform players an update has occurred in their match (like a new player joining or leaving)
            GameSparks.Api.Messages.MatchUpdatedMessage.Listener += OnMatchUpdate;
            #endregion
        }
예제 #17
0
        /// <summary>
        /// Creates an ARCore Cloud Anchor at the location the user tapped and passed into it. This function can be used to set the world origin or just a normal cloud anchor.
        /// It is advisable to only have 1 user in your application set cloud anchors.
        /// </summary>
        /// <param name="_hitResults">Holds information about where the user tapped on the screen. This variable should be created using the ARWorldOriginHelper Raycast method </param>
        /// <param name="_anchorObjectPrefab">The ASL object you want to have located at the cloud anchor. If you don't want any object to be located at the cloud anchor, you can pass in null.
        /// Doing so will create an empty gameobject - thus making it invisible to users</param>
        /// <param name="_myPostCreateCloudAnchorFunction">This is the function you want to call after a cloud anchor has successfully been created. Only the user that called this function
        /// will execute this function - it is not sent to other users. This is a good way to move or create objects after a cloud anchor has been created.</param>
        /// <param name="_waitForAllUsersToResolve">This determines if users should wait to setup (and if they are the caller of this function, to execute the _myPostCreateCloudAnchorFunction)
        /// the cloud anchor once they receive and find it, or if they should wait for all users to receive and find it first before executing anything. The default is to wait for all users
        /// and is the suggested value as not waiting as the potential to cause synchronization problems.</param>
        /// <param name="_setWorldOrigin">This determines if this cloud anchor should be used to set the world origin for all users or not. If you are setting the world origin, you should do
        /// so right away in your app and as the first (if you have more than 1) cloud anchor created. You should never set the world origin more than once.</param>
        public static void CreateARCoreCloudAnchor(TrackableHit _hitResults, ASLObject _anchorObjectPrefab = null, ASLObject.PostCreateCloudAnchorFunction _myPostCreateCloudAnchorFunction = null,
                                                   bool _waitForAllUsersToResolve = true, bool _setWorldOrigin = true)
        {
            if (_anchorObjectPrefab != null)
            {
                if (!_anchorObjectPrefab.m_Mine)
                {
                    Debug.LogError("You must claim the ASL object before setting it as an anchor");
                }
                return;
            }
            //Create local anchor at hit location
            Anchor localAnchor = _hitResults.Trackable.CreateAnchor(_hitResults.Pose);

            localAnchor.name = "Local anchor created when creating cloud anchor";

            //Create CLoud anchor
            XPSession.CreateCloudAnchor(localAnchor).ThenAction(result =>
            {
                //If failed to host
                if (result.Response != CloudServiceResponse.Success)
                {
                    Debug.LogError("Failed to host Cloud Anchor: " + result.Response);
                    return; //Break out
                }
                //Successful:
                Debug.Log("Successfully created and saved Cloud Anchor: " + result.Anchor.CloudId);

                if (_anchorObjectPrefab == null)
                {
                    //Uncomment the line below to aid in visual debugging (helps display the cloud anchor)
                    //_anchorObjectPrefab = GameObject.CreatePrimitive(PrimitiveType.Cube).AddComponent<ASLObject>(); //if null, then create empty game object
                    _anchorObjectPrefab = new GameObject().AddComponent <ASLObject>();
                    _anchorObjectPrefab._LocallySetAnchorID(result.Anchor.CloudId); //Add ASLObject component to this anchor and set its anchor id variable
                    _anchorObjectPrefab._LocallySetID(result.Anchor.CloudId);       //Locally set the id of this object to be that of the anchor id (which is unique)

                    //Add this anchor object to our ASL dictionary using the anchor id as its key. All users will do this once they resolve this cloud anchor to ensure they still in sync.
                    m_ASLObjects.Add(result.Anchor.CloudId, _anchorObjectPrefab.GetComponent <ASLObject>());
                    //_anchorObjectPrefab.GetComponent<Material>().color = Color.magenta;
                    _anchorObjectPrefab.transform.localScale = new Vector3(0.04f, 0.04f, 0.04f); //Set scale to be 4 cm
                }
                else
                {
                    _anchorObjectPrefab.GetComponent <ASLObject>()._LocallySetAnchorID(result.Anchor.CloudId); //Set anchor id variable
                    _anchorObjectPrefab.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);               //Set scale to be 5 cm
                }

                //Send Resolve packet using _anchorObjectPrefab
                _anchorObjectPrefab.GetComponent <ASLObject>().SendCloudAnchorToResolve(_setWorldOrigin, _waitForAllUsersToResolve);

                if (_waitForAllUsersToResolve)
                {
                    //Send packet to relay server letting it know this user is ready
                    using (RTData data = RTData.Get())
                    {
                        data.SetString((int)GameController.DataCode.Id, _anchorObjectPrefab.m_Id);
                        GameSparksManager.Instance().GetRTSession().SendData((int)GameSparksManager.OpCode.ResolvedCloudAnchor, GameSparksRT.DeliveryIntent.RELIABLE, data);
                    }
                    _anchorObjectPrefab.StartWaitForAllUsersToResolveCloudAnchor(result, _setWorldOrigin, _myPostCreateCloudAnchorFunction, _hitResults);
                }
                else //Don't wait for users to know about this cloud anchor
                {
                    _anchorObjectPrefab.GetComponent <ASLObject>()._LocallySetCloudAnchorResolved(true);
                    _anchorObjectPrefab.StartWaitForAllUsersToResolveCloudAnchor(result, _setWorldOrigin, _myPostCreateCloudAnchorFunction, _hitResults);
                }
            });
        }