public void HandleTickSyncMsg(ref TickSyncMsg msg, int connectionId)
        {
            if (GameStatics.OnlineSession.Mode == OnlineSessionMode.Client)
            {
                // Synchronize tick
                float delayTime             = GameStatics.OnlineSession.GetRemoteDelayTimeMS(connectionId, msg.Timestamp) * 0.001f;
                int   ticksFromNetworkDelay = Mathf.FloorToInt(delayTime / Time.fixedDeltaTime);

                // We want to be one half RTT ahead of server in terms of ticks
                SimulationSystem.InitializeAtTick(msg.Tick + ticksFromNetworkDelay + ticksFromNetworkDelay);

                // Send a msg to signal ready
                SimpleEventMsg sem = new SimpleEventMsg();
                sem.Event = SimpleEventMsg.EventType.TickSynced;
                sem.Serialize(GameStatics.OnlineSession.NetBuffer);
                GameStatics.OnlineSession.SendBufferToServer(OnlineSession.ReliableSequencedChannelId);
            }
        }
        public void OnData(int connectionId, int channelId, int receiveSize, int msgId)
        {
            NetworkMessageID iMsgId = (NetworkMessageID)msgId;

            switch (iMsgId)
            {
            case (NetworkMessageID.SceneLoading):
                SceneLoadingMsg slm = new SceneLoadingMsg();
                slm.Deserialize(GameStatics.OnlineSession.NetBuffer);
                HandleLoadSceneMsg(ref slm, connectionId);
                break;

            case (NetworkMessageID.TickSync):
                TickSyncMsg tsm = new TickSyncMsg();
                tsm.Deserialize(GameStatics.OnlineSession.NetBuffer);
                HandleTickSyncMsg(ref tsm, connectionId);
                break;

            case (NetworkMessageID.SimpleEvent):
                SimpleEventMsg sem = new SimpleEventMsg();
                sem.Deserialize(GameStatics.OnlineSession.NetBuffer);
                HandleSimpleEventMsg(connectionId, sem.Event);
                break;

            case (NetworkMessageID.SpawnPlayer):
                SpawnPlayerMsg spm = new SpawnPlayerMsg();
                spm.Deserialize(GameStatics.OnlineSession.NetBuffer);
                HandleSpawnPlayerMsg(ref spm, connectionId);
                break;

            case (NetworkMessageID.SpawnCharacter):
                SpawnCharacterMsg scm = new SpawnCharacterMsg();
                scm.Deserialize(GameStatics.OnlineSession.NetBuffer);
                HandleSpawnCharacterMsg(ref scm);
                break;

            case (NetworkMessageID.LazerHit):
                LazerFireMsg lhm = new LazerFireMsg();
                lhm.Deserialize(GameStatics.OnlineSession.NetBuffer);
                HandleLazerFireMsg(ref lhm);
                break;
            }
        }
        private void OnReadyToInitiateGame()
        {
            int characterCounter = 0;

            // Create and spawn local players & characters
            {
                // Player controller
                MyPlayerController newPlayer = Instantiate(GameStatics.GameData.PlayerPrefab);
                newPlayer.OrbitCamera = Instantiate <OrbitCamera>(GameStatics.GameData.CameraPrefab);
                SimulationSystem.RegisterPlayerController(newPlayer, -1);
                if (GameStatics.OnlineSession.IsOnline())
                {
                    NetworkSpawnPlayer(newPlayer, newPlayer.GetId(), -1);
                }

                // Character
                MyCharacterController newCharacter = Instantiate(GameStatics.GameData.CharacterPrefab);
                newPlayer.OrbitCamera.SetFollowTransform(newCharacter.CameraFollowPoint);
                newPlayer.OrbitCamera.IgnoredColliders = newCharacter.GetComponentsInChildren <Collider>();
                PlaceCharacterAtSpawnPointIndex(newCharacter, characterCounter);
                KinematicCharacterSubsystem.RegisterCharacter(newCharacter, true);
                if (GameStatics.OnlineSession.IsOnline())
                {
                    NetworkSpawnCharacter(newCharacter, newCharacter.GetId(), newPlayer.GetId());
                }

                // Assign character to player
                newPlayer.Character       = newCharacter;
                newCharacter.OwningPlayer = newPlayer;

                characterCounter++;
            }

            // Create and spawn client players & characters
            foreach (ConnectionInfo ci in ConnectionInfos)
            {
                // Player controller
                MyPlayerController newPlayer = Instantiate(GameStatics.GameData.PlayerPrefab);
                SimulationSystem.RegisterPlayerController(newPlayer, ci.ConnectionId);
                if (GameStatics.OnlineSession.IsOnline())
                {
                    NetworkSpawnPlayer(newPlayer, newPlayer.GetId(), ci.ConnectionId);
                }

                // Register as player for that connection
                ci.PlayerControllerIds.Add(newPlayer.GetId());

                // Character
                MyCharacterController newCharacter = Instantiate(GameStatics.GameData.CharacterPrefab);
                PlaceCharacterAtSpawnPointIndex(newCharacter, characterCounter);
                KinematicCharacterSubsystem.RegisterCharacter(newCharacter, false);
                if (GameStatics.OnlineSession.IsOnline())
                {
                    NetworkSpawnCharacter(newCharacter, newCharacter.GetId(), newPlayer.GetId());
                }

                // Assign character to player
                newPlayer.Character       = newCharacter;
                newCharacter.OwningPlayer = newPlayer;

                characterCounter++;
            }

            // Tell clients to initiate game
            if (GameStatics.OnlineSession.IsOnline())
            {
                SimpleEventMsg sem = new SimpleEventMsg();
                sem.Event = SimpleEventMsg.EventType.InitiateGame;
                sem.Serialize(GameStatics.OnlineSession.NetBuffer);
                GameStatics.OnlineSession.SendBufferToAllClients(OnlineSession.ReliableSequencedChannelId);
            }
        }