public void SendGunfireDataToServer(FPSCharController.HitData getData)
        {
            Debug.Log("[Notice] Sending gunfire data to server...");

            string        msgJson;
            MissShotsData gunfireMissMsg;
            HitScanData   gunfireHitMsg;

            Byte[] sendBytes;

            if (getData.is_hit)
            {
                gunfireHitMsg = new HitScanData(getData.hit_origin_name, getData.hit_name, new Coordinates(getData.hit_location.x, getData.hit_location.y, getData.hit_location.z), getData.damage, getData.is_hit);
                msgJson       = JsonUtility.ToJson(gunfireHitMsg);
            }
            else
            {
                gunfireMissMsg = new MissShotsData(getData.hit_origin_name, new Coordinates(getData.hit_location.x, getData.hit_location.y, getData.hit_location.z));
                msgJson        = JsonUtility.ToJson(gunfireMissMsg);
            }

            sendBytes = Encoding.ASCII.GetBytes(msgJson);
            udp.Send(sendBytes, sendBytes.Length);
        }
        //Process the network messages sent by the server. We stored them in a queue during OnReceived(). TODO incomplete
        private void ProcessServerMessages()
        {
            //Only process this function if there is data in queue
            if (dataQueue.Count <= 0)
            {
                return;
            }

            if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.CONNECT)
            {
                isConnected     = true;
                showIfConnected = isConnected;

                if (bDebug)
                {
                    Debug.Log("[Notice] Client connection established with " + udp.Client.RemoteEndPoint.ToString() + ".");
                }
                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] Client connection established with server.");
                }
                Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");
                dataQueue.Dequeue();
            }
            else if (!isConnected)
            {
                Debug.LogError("[Error] Received message from server, but cannot process it because client is not connected to server.");
                dataQueue.Clear();
                return;
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.CREATE_ACCOUNT)
            {
                if (bDebug)
                {
                    Debug.Log("[Notice] New account created.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] Account created successfully.");
                }
                Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");

                if (loginCtrlRef)
                {
                    loginCtrlRef.AccountCreated();
                }
                else if (GameObject.Find("Canvas/Login Controller"))
                {
                    loginCtrlRef = GameObject.Find("Canvas/Login Controller").GetComponent <LoginController>();
                    loginCtrlRef.AccountCreated();
                }

                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.FAILED_ACCOUNT_CREATION)
            {
                if (bDebug)
                {
                    Debug.Log("[Notice] Failed to create new account.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] Failed to create account; Invalid username or password.");
                }

                if (loginCtrlRef)
                {
                    loginCtrlRef.UserExists();
                }
                else if (GameObject.Find("Canvas/Login Controller"))
                {
                    loginCtrlRef = GameObject.Find("Canvas/Login Controller").GetComponent <LoginController>();
                    loginCtrlRef.UserExists();
                }

                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.LOGIN_ACCOUNT)
            {
                isLoggedIn = true;
                GameStateManager.SetState(State.GAMESELECTSCENE);
                if (bDebug)
                {
                    Debug.Log("[Notice] Client has successfully logged in.");
                }

                //TODO: Exit login screen; Load next scene

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] Successfully logged in.");
                }
                Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");

                if (loginCtrlRef)
                {
                    loginCtrlRef.ConfirmServerLogin();
                }
                else if (GameObject.Find("Canvas/Login Controller"))
                {
                    loginCtrlRef = GameObject.Find("Canvas/Login Controller").GetComponent <LoginController>();
                    loginCtrlRef.ConfirmServerLogin();
                }

                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.FAILED_LOGIN)
            {
                if (bDebug)
                {
                    Debug.Log("[Notice] Failed to log in.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] Login failed; Invalid username or password.");
                }

                if (loginCtrlRef)
                {
                    loginCtrlRef.IncorrectLogin();
                }
                else if (GameObject.Find("Canvas/Login Controller"))
                {
                    loginCtrlRef = GameObject.Find("Canvas/Login Controller").GetComponent <LoginController>();
                    loginCtrlRef.IncorrectLogin();
                }

                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.PING)  //Received a ping from the server
            {
                if (bDebug && bVerboseDebug)
                {
                    Debug.Log("[Routine] Received flag from server: PING.");
                }
                ResponsePong(); //Send a response pong message
                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.VERSION)  //Receives a version request from server. Note: Not used in this case as the client sends the version with the first CONNECT message
            {
                if (bDebug)
                {
                    Debug.Log("[Routine] Received flag from server: VERSION.");
                }
                ResponseVersion();
                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.INVALID_VERSION)  //Receives an invalid version message from server
            {
                if (bDebug)
                {
                    Debug.Log("[Notice] Received flag from server: INVALID_VERSION.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] Incompatible client version; disconnecting from server...");
                }

                Disconnect();
                dataQueue.Dequeue();
            }
            else if (!isLoggedIn)
            {
                Debug.LogError("[Error] Received message from server, but cannot process it because client is not logged in.");
                dataQueue.Dequeue();
                return;
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.QUEUE_MATCHMAKING)
            {
                isInMMQueue = true;
                if (bDebug)
                {
                    Debug.Log("[Notice] Received flag from server: QUEUE_MATCHMAKING.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] You have joined matchmaking queue.");
                }
                Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");
                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.FAILED_MMQUEUE)
            {
                if (bDebug)
                {
                    Debug.Log("[Notice] Received flag from server: FAILED_MMQUEUE.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] You have failed to join matchmaking queue.");
                }
                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.MATCH_START)
            {
                MoveUpdateData playersData = JsonUtility.FromJson <MoveUpdateData>(dataQueue.Peek());
                isInMatch = true;

                //Receive lobby data
                foreach (PlayerMoveData player in playersData.players)
                {
                    //Update player position and orientation data, and health
                    //Adds players to clientDataDict that aren't added yet
                    UpdatePlayer(player.username, player.position.x, player.position.y, player.position.z, player.orientation.yaw, player.orientation.pitch, player.health);
                }

                if (bDebug)
                {
                    Debug.Log("[Notice] Client's game match has started.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] The match is starting...");
                }
                Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");

                if (!selectCtrlRef)
                {
                    if (GameObject.Find("SelectionController"))
                    {
                        selectCtrlRef = GameObject.Find("SelectionController").GetComponent <SelectionController>();
                        selectCtrlRef.MatchmakingComplete();
                    }
                }
                else
                {
                    selectCtrlRef.MatchmakingComplete();
                }

                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.LEAVE_MATCHMAKING)
            {
                isInMMQueue = false;
                isInMatch   = false;

                if (bDebug)
                {
                    Debug.Log("[Notice] Client has left matchmaking queue.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] You have left matchmaking queue.");
                }
                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.FETCH_ACCOUNT)
            {
                if (bDebug)
                {
                    Debug.Log("[Notice] Retrieved profile data.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] Retrieved profile data.");
                }
                Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");

                if (!profileMgrRef)
                {
                    if (GameObject.Find("ProfileManager"))
                    {
                        profileMgrRef = GameObject.Find("ProfileManager").GetComponent <ProfileMgr>();
                        profileMgrRef.SetProfile(clientUsername, 1500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); //TODO TEMP
                        clientUsername = profileMgrRef._Username;
                    }
                }
                else
                {
                    profileMgrRef.SetProfile(clientUsername, 1500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); //TODO TEMP
                    clientUsername = profileMgrRef._Username;
                }

                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.FAILED_FETCH)
            {
                if (bDebug)
                {
                    Debug.Log("[Notice] Failed to retrieve profile data.");
                }

                if (consoleRef)
                {
                    consoleRef.UpdateChat("[Console] Failed to retrieve profile data.");
                }
                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.MATCH_UPDATE)
            {
                MoveUpdateData playersData = JsonUtility.FromJson <MoveUpdateData>(dataQueue.Peek());
                if (bDebug && bVerboseDebug)
                {
                    Debug.Log("[Notice] Received Match Update.");
                }

                if (bDebug && bVerboseDebug)
                {
                    Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");
                }

                //Receive lobby data
                foreach (PlayerMoveData player in playersData.players)
                {
                    //Update player position and orientation data, and health
                    //Adds players to clientDataDict that aren't added yet
                    UpdatePlayer(player.username, player.position.x, player.position.y, player.position.z, player.orientation.yaw, player.orientation.pitch, player.health);
                }

                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.MISSSHOT_UPDATE)
            {
                MissShotsData shotData = JsonUtility.FromJson <MissShotsData>(dataQueue.Peek());
                Debug.Log("[Temp Debug] dataQueue.Count: " + dataQueue.Count);
                dataQueue.Dequeue();

                Debug.Log("[Notice] Received Missed Shot Update.");
                if (bDebug && bVerboseDebug)
                {
                    Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");
                }

                //Dont process gunshots from own client
                if (shotData.usernameOrigin == clientUsername)
                {
                    Debug.Log("    [Notice] Will not process own gunshots...");
                    return;
                }

                if (!gameMgrRef)
                {
                    if (GameObject.Find("GameManager"))
                    {
                        gameMgrRef = GameObject.Find("GameManager").GetComponent <GameplayManager>();
                    }
                }

                if (gameMgrRef)
                {
                    if (clientDataDict.ContainsKey(shotData.usernameOrigin))
                    {
                        StartCoroutine(gameMgrRef.ConveyMissShot(clientDataDict[shotData.usernameOrigin].objChaserReference, new Vector3(shotData.hitPosition.x, shotData.hitPosition.y, shotData.hitPosition.z)));
                    }
                    else
                    {
                        Debug.LogError("[Error] shotData.usernameOrigin is not a valid key in clientDataDict; cannot update miss shot.");
                    }
                }
                else
                {
                    Debug.LogError("[Error] GameplayManager reference missing; cannot update miss shot.");
                }
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.HITSCAN_UPDATE)
            {
                HitScanData shotData = JsonUtility.FromJson <HitScanData>(dataQueue.Peek());

                Debug.Log("[Notice] Received Hit Scan Update.");
                if (bDebug && bVerboseDebug)
                {
                    Debug.Log("[TEMP TEST] Active Scene is '" + SceneManager.GetActiveScene().name + "'.");
                }

                //Dont process gunshots from own client
                if (shotData.usernameOrigin == clientUsername)
                {
                    return;
                }

                if (!gameMgrRef)
                {
                    if (GameObject.Find("GameManager"))
                    {
                        gameMgrRef = GameObject.Find("GameManager").GetComponent <GameplayManager>();
                    }
                }

                if (gameMgrRef)
                {
                    if (clientDataDict.ContainsKey(shotData.usernameOrigin) && clientDataDict.ContainsKey(shotData.usernameTarget))
                    {
                        if (shotData.damage == 0)   //TODO BANDAID FIX
                        {
                            shotData.damage = 20;
                        }

                        //subtract from health
                        if (clientDataDict[shotData.usernameTarget].health - shotData.damage <= 0)
                        {
                            clientDataDict[shotData.usernameTarget].health = 0;
                            StartCoroutine(BandaidDeathRoutine());
                            //SendDeathMessage(shotData.usernameOrigin, shotData.usernameTarget);
                        }
                        else if (clientDataDict[shotData.usernameTarget].health - shotData.damage > 100)
                        {
                            clientDataDict[shotData.usernameTarget].health = 100;
                        }
                        else
                        {
                            clientDataDict[shotData.usernameTarget].health = clientDataDict[shotData.usernameTarget].health - shotData.damage;
                        }

                        Debug.Log("[Notice] health: " + clientDataDict[shotData.usernameTarget].health);

                        if (shotData.usernameTarget == clientUsername)
                        {
                            //update health bar
                            if (!hpBarCtrlRef)
                            {
                                hpBarCtrlRef = GameObject.Find("Canvas/Health").GetComponent <HealthController>();
                            }
                            if (hpBarCtrlRef)
                            {
                                hpBarCtrlRef.HitMe();
                            }
                            StartCoroutine(gameMgrRef.ConveyHitShot(clientDataDict[shotData.usernameOrigin].objChaserReference, clientDataDict[shotData.usernameTarget].objReference, new Vector3(shotData.hitPosition.x, shotData.hitPosition.y, shotData.hitPosition.z), shotData.damage));
                        }
                        else
                        {
                            StartCoroutine(gameMgrRef.ConveyHitShot(clientDataDict[shotData.usernameOrigin].objChaserReference, clientDataDict[shotData.usernameTarget].objChaserReference, new Vector3(shotData.hitPosition.x, shotData.hitPosition.y, shotData.hitPosition.z), shotData.damage));
                        }
                        Debug.Log("[Notice] " + shotData.usernameTarget + " received " + shotData.damage + " gunfire damage from " + shotData.usernameOrigin);
                    }
                    else
                    {
                        Debug.LogError("[Error] shotData.usernameOrigin is not a valid key in clientDataDict; cannot update hit shot.");
                    }
                }
                else
                {
                    Debug.LogError("[Error] GameplayManager reference missing; cannot update hit shot.");
                }
                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.RESPAWN)
            {
                RespawnMessage spawnData = JsonUtility.FromJson <RespawnMessage>(dataQueue.Peek());

                Debug.Log("[Notice] Received respawn message.");

                Respawn(new Vector3(spawnData.spawn.x, spawnData.spawn.y, spawnData.spawn.z));
                dataQueue.Dequeue();
            }
            else if (JsonUtility.FromJson <FlagNetMsg>(dataQueue.Peek()).flag == Flag.MATCH_END)
            {
                dataQueue.Dequeue();
            }
        }