// this is  for _host only_ to send messages to themself
        public void SendMatchStateMessageSelf <T>(MatchMessageType opCode, T message)
            where T : MatchMessage <T>
        {
            Debug.LogError("Sending Match Data to Self");
            // TODO: add more cases
            switch (opCode)
            {
            case MatchMessageType.AsteroidSpawned:
                OnAsteroidSpawned?.Invoke(message as MatchMessageSpawnElement);
                break;

            case MatchMessageType.PlayerSpawned:
                OnPlayerSpawned?.Invoke(message as MatchMessageSpawnShip);
                break;

            case MatchMessageType.BallSpawned:
                OnBallSpawned?.Invoke(message as MatchMessageSpawnElement);
                break;

            case MatchMessageType.GoalSpawned:
                OnGoalSpawned?.Invoke(message as MatchMessageSpawnElement);
                break;

            case MatchMessageType.StadiumEntered:
                OnStadiumEntered?.Invoke();
                break;
            }
        }
        public void ReceiveMatchStateHandle(long opCode, string messageJson)
        {
            if (GameStarted == false)
            {
                inboundMessages.Enqueue(new IncommingMessageState(opCode, messageJson));
            }

            switch ((MatchMessageType)opCode)
            {
            case MatchMessageType.MatchEnded:
                break;

            case MatchMessageType.AsteroidSpawned:
                MatchMessageSpawnElement asteroidSpawn = MatchMessageSpawnElement.Parse(messageJson);
                OnAsteroidSpawned?.Invoke(asteroidSpawn);
                break;

            case MatchMessageType.StadiumEntered:
                OnStadiumEntered?.Invoke();
                break;

            case MatchMessageType.PlayerSpawned:
                MatchMessageSpawnShip playerSpawn = MatchMessageSpawnShip.Parse(messageJson);
                OnPlayerSpawned?.Invoke(playerSpawn);
                break;

            case MatchMessageType.BallSpawned:
                MatchMessageSpawnElement ballSpawn = MatchMessageSpawnElement.Parse(messageJson);
                OnBallSpawned?.Invoke(ballSpawn);
                break;

            case MatchMessageType.GoalSpawned:
                MatchMessageSpawnElement goalSpawn = MatchMessageSpawnElement.Parse(messageJson);
                OnGoalSpawned?.Invoke(goalSpawn);
                break;

            case MatchMessageType.AsteroidPositionUpdated:
            {
                UnityMainThreadDispatcher.Instance().Enqueue(() =>
                    {
                        var d = messageJson.FromJson <MatchMessageAsteroidPositionUpdated>();
                        OnAsteroidPositionUpdated?.Invoke(d.id, d.x, d.y);
                    });

                break;
            }

            case MatchMessageType.PlayerPositionUpdated:
            {
                var positionValues = messageJson.FromJson <MatchMessagePositionUpdated>();

                var posX  = positionValues.posX;
                var posY  = positionValues.posY;
                var angle = positionValues.angle;
                var id    = positionValues.id;

                UnityMainThreadDispatcher.Instance().Enqueue(() =>
                    {
                        OnPlayerPositionUpdated?.Invoke(posX, posY, angle, id);
                    });
            }
            break;

            case MatchMessageType.PlayerInputRotationUpdated:
            {
                var value = messageJson.FromJson <MatchMessageInputRotationUpdated>();

                var input = value.input;
                var id    = value.id;

                UnityMainThreadDispatcher.Instance().Enqueue(() =>
                    {
                        OnPlayerInputRotationUpdated?.Invoke(input, id);
                    });
            }
            break;

            case MatchMessageType.PlayerInputThrustUpdated:
            {
                var value = messageJson.FromJson <MatchMessageInputThrustUpdated>();

                var input = value.input;
                var id    = value.id;

                UnityMainThreadDispatcher.Instance().Enqueue(() =>
                    {
                        OnPlayerInputThrustUpdated?.Invoke(input, id);
                    });
            }

            break;

            case MatchMessageType.BallPositionUpdated:
            {
                var positionValues = messageJson.FromJson <MatchMessageBallPositionUpdated>();

                var posX  = positionValues.posX;
                var posY  = positionValues.posY;
                var angle = positionValues.angle;
                var id    = positionValues.id;

                UnityMainThreadDispatcher.Instance().Enqueue(() =>
                    {
                        OnBallPositionUpdated?.Invoke(posX, posY, angle, id);
                    });
            }
            break;

            default:
                Debug.Log("Needs more implementation!");
                break;
            }
        }