示例#1
0
        public bool IsPredictionCorrect(SnapshotWithLastInputId correctServerSnapshot, ushort playerEntityId)
        {
            PredictedSnapshot predictedSnapshot = predictedSnapshotsStorage
                                                  .GetByInputId(correctServerSnapshot.lastProcessedInputId);

            if (predictedSnapshot == null)
            {
                string mes = $"Не найдено предсказанное состояние. lastProcessedInputId = {correctServerSnapshot.lastProcessedInputId}";
                throw new Exception(mes);
            }

            bool timeIsSame = correctServerSnapshot.lastProcessedInputId == predictedSnapshot.lastInputId;

            if (!timeIsSame)
            {
                string message = "Время снимков не совпадает. " +
                                 $" inputId тика с сервера = {correctServerSnapshot.lastProcessedInputId} " +
                                 $" inputId предсказанного тика = {predictedSnapshot.lastInputId}";
                throw new ArgumentException(message);
            }

            bool isPredictionCorrect = playerEntityComparer
                                       .IsSame(predictedSnapshot, correctServerSnapshot, playerEntityId);

            return(isPredictionCorrect);
        }
 public void Execute()
 {
     try
     {
         int newestTickNumber = snapshotBuffer.GetNewestTickNumber();
         //Пришла новая информация
         if (lastSavedTickNumber < newestTickNumber)
         {
             //Обновить локальный счётчик
             lastSavedTickNumber = newestTickNumber;
             SnapshotWithLastInputId newest = snapshotBuffer.GetNewestSnapshot();
             ushort playerEntityId          = PlayerIdStorage.PlayerEntityId;
             if (playerEntityId == 0)
             {
                 //todo изменить порядок установки playerEntityId
                 throw new Exception("PlayerEntityId не установлен");
             }
             //проверить, что игрок правильно предсказан или пересоздать текущее состояние
             predictionManager.Reconcile(newest, playerEntityId);
         }
         else
         {
             //новый тик от сервера не пришёл
         }
     }
     catch (Exception e)
     {
         log.Error(e.FullMessage());
     }
 }
示例#3
0
        public void SetNewTransforms(TransformPackMessage message)
        {
            SnapshotWithLastInputId snapshot = new SnapshotWithLastInputId(message);

            snapshotBuffer.Add(snapshot);

            timeUpdater.NewSnapshotReceived(message.TickNumber, message.TickStartTimeSec);
        }
示例#4
0
        public void Resimulate(SnapshotWithLastInputId correctServerSnapshot,
                               ushort playerEntityId)
        {
            log.Info($"Пересчёт тика inputId = {correctServerSnapshot.lastProcessedInputId}.");

            ReplaceWrongSnapshot(correctServerSnapshot);
            ResimulateSnapshots(correctServerSnapshot, playerEntityId);
        }
示例#5
0
        private void ReplaceWrongSnapshot(SnapshotWithLastInputId correctServerSnapshot)
        {
            PredictedSnapshot wrongSnapshot = predictedSnapshotsStorage
                                              .GetByInputId(correctServerSnapshot.lastProcessedInputId);

            //изменение ошибочного снимка
            // ReSharper disable once PossibleNullReferenceException
            wrongSnapshot.Clear();
            wrongSnapshot.Modify(correctServerSnapshot);

            //todo это можно не делать
            predictedSnapshotsStorage.PutCorrect(wrongSnapshot);
        }
        public void Execute()
        {
            int newestTickNumber = snapshotBuffer.GetNewestTickNumber();

            if (newestTickNumber == lastShowedTickNumber)
            {
                return;
            }

            lastShowedTickNumber = newestTickNumber;
            SnapshotWithLastInputId newestGameState = snapshotBuffer.GetNewestSnapshot();

            HashSet <ushort> needDelete = new HashSet <ushort>(dictionary.Keys);

            foreach (var pair in newestGameState.transforms)
            {
                ushort entityId      = pair.Key;
                var    viewTransform = pair.Value;

                Vector3    position = viewTransform.GetPosition();
                Quaternion rotation = Quaternion.AngleAxis(viewTransform.Angle, Vector3.up);

                if (!vectorValidator.TryValidate(position))
                {
                    log.Debug("Проблема позиции");
                    continue;
                }

                needDelete.Remove(entityId);
                //Такой обьект уже есть на сцене
                if (dictionary.TryGetValue(entityId, out var gameObject))
                {
                    //Обновить
                    gameObject.transform.position = position;
                    gameObject.transform.rotation = rotation;
                }
                else
                {
                    //Создать
                    GameObject prefab = clientPrefabsStorage.GetPrefab(viewTransform.viewTypeEnum);
                    GameObject go     = physicsSpawner.Spawn(prefab, position, rotation);
                    dictionary.Add(entityId, go);
                }
            }

            //Удалить лишние объекты
            foreach (ushort entityId in needDelete)
            {
                Object.Destroy(dictionary[entityId]);
            }
        }
示例#7
0
 public void Add(SnapshotWithLastInputId snapshotArg)
 {
     lock (lockObj)
     {
         // log.Info($"Добавление нового тика № = {snapshotArg.tickNumber} time = {snapshotArg.tickTime}");
         if (history.TryGetValue(snapshotArg.tickNumber, out var snapshot))
         {
             snapshot.Modify(snapshotArg);
         }
         else
         {
             history.Add(snapshotArg.tickNumber, snapshotArg);
         }
     }
 }
示例#8
0
        private void ResimulateSnapshots(SnapshotWithLastInputId correctServerSnapshot, ushort playerEntityId)
        {
            //достать все вводы после заменённого снимка
            var allInputs = clientInputMessagesHistory
                            .GetAllFromId(correctServerSnapshot.lastProcessedInputId);
            List <AverageInputMessageModel> averageInputs = averageInputManager.GetAverageInputs(allInputs);

            log.Debug($"Кол-во вводов {allInputs.Count}. Кол-во тиков физики = {averageInputs.Count}");
            DateTime startTime = DateTime.UtcNow;

            //вызвать перегенерцию положения игрока для каждого ввода
            foreach (var averageInput in averageInputs)
            {
                //todo взять суммарную длительность тиков
                float physicsSimulationDuration = predictedSnapshotUtil
                                                  .GetTotalDuration(averageInput.replacedInputsIds, predictedSnapshotsStorage);
                log.Debug("Длительность симуляции " + physicsSimulationDuration);
                var baseSnapshot = predictedSnapshotsStorage.GetByInputId(averageInput.inputId - 1)
                                   ?? throw new NullReferenceException();


                if (baseSnapshot.lastInputId != averageInput.inputId - 1)
                {
                    throw new Exception("Не совпадает lastInputId");
                }

                log.Debug($"Пересчёт снимка {averageInput.inputId}");
                Snapshot snapshot = playerPredictor.Predict(baseSnapshot, playerEntityId,
                                                            averageInput.inputMessageModel, physicsSimulationDuration);

                foreach (uint inputId in averageInput.replacedInputsIds)
                {
                    var wrongPredictedSnapshot = predictedSnapshotsStorage.GetByInputId(inputId)
                                                 ?? throw new NullReferenceException();
                    wrongPredictedSnapshot.Clear();
                    wrongPredictedSnapshot.Modify(snapshot);
                }
            }

            DateTime finishTime    = DateTime.UtcNow;
            int      reconcileTime = (finishTime - startTime).Milliseconds;

            log.Debug($"reconcileTime = {reconcileTime}");
        }
示例#9
0
        public void Reconcile(SnapshotWithLastInputId correctServerSnapshot, ushort playerEntityId)
        {
            uint lastProcessedInputId = correctServerSnapshot.lastProcessedInputId;

            if (lastProcessedInputId == 0)
            {
                log.Debug("С сервера пришёл тик с пустым lastProcessedInputId");
                return;
            }

            if (!predictionChecker.IsPredictionCorrect(correctServerSnapshot, playerEntityId))
            {
                simulationCorrector.Resimulate(correctServerSnapshot, playerEntityId);
            }
            else
            {
                // log.Info($"Правильное предсказание inputId = {lastProcessedInputId}");
            }
        }