예제 #1
0
 internal void Reset()
 {
     _physicsGameTime.Reset(TimeSpan.Zero);
     SimulationTickNumber   = default;
     CurrentTickTimeElapsed = TimeSpan.Zero;
     TotalTime = TimeSpan.Zero;
 }
예제 #2
0
 internal static ref MovementSnapshotsComponent.MovementData CreateNewSnapshotData(
     FastList <MovementSnapshotsComponent.MovementData> predictedMovements,
     SimulationTickNumber simulationTickNumber,
     MovementSnapshotsComponent movementSnapshotsComponent,
     TransformComponent transformComponent)
 {
     predictedMovements.Add(default);
예제 #3
0
        public FindSnapshotResult TryFindSnapshotClosestEqualOrLessThan(SimulationTickNumber simTickNumber)
        {
            bool isFound          = false;
            var  closestSimTickNo = new SimulationTickNumber(0);
            int  closestIndex     = -1;

            for (int i = 0; i < _snapshotRingBuffer.Count; i++)
            {
                var curSimTickNo = _snapshotRingBuffer[i].SimulationTickNumber;
                if (simTickNumber == curSimTickNo)
                {
                    return(new FindSnapshotResult(_snapshotRingBuffer, i));
                }
                else if (curSimTickNo < simTickNumber && curSimTickNo > closestSimTickNo)
                {
                    isFound          = true;
                    closestSimTickNo = curSimTickNo;
                    closestIndex     = i;
                }
            }
            if (isFound)
            {
                return(new FindSnapshotResult(_snapshotRingBuffer, closestIndex));
            }
            else
            {
                return(FindSnapshotResult.NotFound);
            }
        }
예제 #4
0
        public static SimulationTickNumber CalculateSimulationTickNumber(TimeSpan totalTime)
        {
            // This always rounds down.
            var simTickNo = new SimulationTickNumber(totalTime.Ticks / GameConfig.PhysicsFixedTimeStep.Ticks);

            return(simTickNo);
        }
예제 #5
0
        public static TimeSpan CalculateTickTimeElapsed(TimeSpan totalTime, SimulationTickNumber simulationTickNumber)
        {
            var simTickTime = TimeSpan.FromTicks(simulationTickNumber * GameConfig.PhysicsFixedTimeStep.Ticks);
            var timeElapsed = totalTime - simTickTime;

            return(timeElapsed);
        }
예제 #6
0
            internal void SendClientInputPredictionsToServer(SimulationTickNumber currentSimTickNumber, NetworkMessageWriter networkMessageWriter)
            {
                for (int playerIdx = 0; playerIdx < _localPlayers.Count; playerIdx++)
                {
                    ref var player             = ref _localPlayers.Items[playerIdx];
                    var     inputSnapshotsComp = player.InputSnapshotsComponent;

                    PlayerUpdateMessage playerUpdateMsg = default;

                    var pendingInputs = inputSnapshotsComp.PendingInputs;
                    // Need to limit the number of input, eg. if there's a large delay in server ack response,
                    // then most likely it has lost some of our older input. Probably should be a config setting?
                    const int MaxPendingPlayerInputs = GameConfig.PhysicsSimulationRate * 20; // 20s worth of input
                    const int MaxSendPlayerInputs    = 10;                                    // We will only send 10 inputs max in a single packet, and accept the fact that older inputs may be lost
                    if (pendingInputs.Count >= MaxPendingPlayerInputs)
                    {
                        pendingInputs.RemoveRange(0, pendingInputs.Count - MaxPendingPlayerInputs + 1);
                    }
                    // Append the latest input
                    var findSnapshotResult = inputSnapshotsComp.SnapshotStore.TryFindSnapshot(currentSimTickNumber);
                    Debug.Assert(findSnapshotResult.IsFound);
                    pendingInputs.Add(findSnapshotResult.Result);

                    int sendInputCount = Math.Min(pendingInputs.Count, MaxSendPlayerInputs);
                    // At most, only send the last 10 inputs (ie. the current inputs) to not blow out the packet size.
                    int inputIndexOffset = pendingInputs.Count - sendInputCount;
                    for (int i = 0; i < sendInputCount; i++)
                    {
                        int inputIndex = i + inputIndexOffset;
                        if (pendingInputs[inputIndex].PlayerInputSequenceNumber > inputSnapshotsComp.ServerLastAcknowledgedPlayerInputSequenceNumber)
                        {
                            inputIndexOffset += i;
                            sendInputCount   -= i;
                            break;
                        }
                    }

                    networkMessageWriter.Reset();
                    playerUpdateMsg.AcknowledgedServerSimulationTickNumber = player.NetworkEntityComponent.LastAcknowledgedServerSimulationTickNumber;
                    playerUpdateMsg.WriteTo(networkMessageWriter);
                    PlayerUpdateInputMessage playerUpdateInputsMsg = default;
                    playerUpdateInputsMsg.WriteHeader(networkMessageWriter, (ushort)sendInputCount);

                    for (int i = 0; i < sendInputCount; i++)
                    {
                        int     inputIndex   = i + inputIndexOffset;
                        ref var curInputData = ref pendingInputs.Items[inputIndex];
                        playerUpdateInputsMsg.PlayerInputSequenceNumber = curInputData.PlayerInputSequenceNumber;
                        playerUpdateInputsMsg.MoveInput          = curInputData.MoveInput;
                        playerUpdateInputsMsg.JumpRequestedInput = curInputData.IsJumpButtonDown;

                        playerUpdateInputsMsg.WriteNextArrayItem(networkMessageWriter);
#if DEBUG
                        //if (curInputData.MoveInput.LengthSquared() > 0)
                        //{
                        //    _networkEntityProcessor.DebugWriteLine($"Cln SendInput Move: {curInputData.MoveInput} - PISeqNo: {curInputData.PlayerInputSequenceNumber}");
                        //}
#endif
                    }
예제 #7
0
 private static void SetPlayerTransform(
     SimulationTickNumber simulationTickNumber,
     MovementSnapshotsComponent movementSnapshotsComponent,
     CharacterComponent characterComponent,
     ref Vector3 position,
     ref Quaternion rotation)
 {
     Debug.Assert(movementSnapshotsComponent != null);
     ref var movementData = ref movementSnapshotsComponent.SnapshotStore.GetOrCreate(simulationTickNumber);
예제 #8
0
        public ref T GetOrCreate(SimulationTickNumber simTickNumber)
        {
            var findResult = TryFindSnapshot(simTickNumber);

            if (findResult.IsFound)
            {
                return(ref findResult.Result);
            }
            else
            {
                _snapshotRingBuffer.Add(default);
예제 #9
0
        public bool Read(out SimulationTickNumber value)
        {
            if (_reader.TryGetLong(out var innerValue))
            {
                value = new SimulationTickNumber(innerValue);
                return(true);
            }

            value = default;
            return(false);
        }
예제 #10
0
        public FindSnapshotResult TryFindSnapshot(SimulationTickNumber simTickNumber)
        {
            var  matcher = new MatchEqualToSimNumber(simTickNumber);
            bool isFound = _snapshotRingBuffer.TryFindLastIndex(matcher, out int index);

            if (isFound)
            {
                return(new FindSnapshotResult(_snapshotRingBuffer, index));
            }
            else
            {
                return(FindSnapshotResult.NotFound);
            }
        }
예제 #11
0
        private Entity CreateAndAddClientPlayerEntity(
            SimulationTickNumber simulationTickNumber,
            SerializableGuid playerId,
            string playerName,
            ref Vector3 position,
            ref Quaternion rotation,
            bool isLocalEntity)
        {
            var gameplayScene    = _lazyLoadedScene.GetGameplayScene();
            var assetDefinitions = _lazyLoadedScene.GetNetworkAssetDefinitions();

            Debug.Assert(!_networkEntityIdToEntityDataMap.ContainsKey(playerId));

            var networkEntityId      = playerId;
            var prefabUrl            = isLocalEntity ? assetDefinitions.PlayerAssets.ClientLocalPlayer : assetDefinitions.PlayerAssets.ClientRemotePlayer;
            var prefab               = _content.Load(prefabUrl);
            var clientPlayerEntities = prefab.InstantiateClientPlayer();

            var playerEntity      = clientPlayerEntities.PlayerEntity;
            var networkPlayerComp = playerEntity.Get <NetworkPlayerComponent>();

            networkPlayerComp.PlayerName = playerName;

            var networkEntityComp = playerEntity.Get <NetworkEntityComponent>();

            networkEntityComp.NetworkEntityId = networkEntityId;
            networkEntityComp.OwnerClientId   = playerId;
            networkEntityComp.AssetId         = _networkAssetDatabase.GetAssetIdFromUrlReference(prefabUrl);

            AddAndRegisterEntity(playerEntity, gameplayScene, simulationTickNumber);
            // Set initial position
            var data = _networkEntityIdToEntityDataMap[networkEntityId];
            var movementSnapshotsComp = data.MovementSnapshotsComponent;
            var characterComp         = data.CharacterComponent;

            SetPlayerTransform(simulationTickNumber, movementSnapshotsComp, characterComp, ref position, ref rotation);

            // The 'viewable' player is added separately
            var playerViewEntity = clientPlayerEntities.PlayerViewEntity;

            gameplayScene.Entities.Add(playerViewEntity);

            return(playerEntity);
        }
예제 #12
0
        public FindSnapshotResult TryFindSnapshotClosestAnyDirection(SimulationTickNumber simTickNumber)
        {
            bool isFound = false;
            var  closestSimTickNoGreater = new SimulationTickNumber(long.MaxValue);
            int  closestIndexGreater     = -1;
            var  closestSimTickNoLesser  = new SimulationTickNumber(0);
            int  closestIndexLesser      = -1;

            for (int i = 0; i < _snapshotRingBuffer.Count; i++)
            {
                var curSimTickNo = _snapshotRingBuffer[i].SimulationTickNumber;
                if (simTickNumber == curSimTickNo)
                {
                    return(new FindSnapshotResult(_snapshotRingBuffer, i));
                }
                if (curSimTickNo > simTickNumber && curSimTickNo < closestSimTickNoGreater)
                {
                    isFound = true;
                    closestSimTickNoGreater = curSimTickNo;
                    closestIndexGreater     = i;
                }
                if (curSimTickNo < simTickNumber && curSimTickNo > closestSimTickNoLesser)
                {
                    isFound = true;
                    closestSimTickNoLesser = curSimTickNo;
                    closestIndexLesser     = i;
                }
            }
            if (isFound)
            {
                if ((closestSimTickNoGreater - simTickNumber) < (simTickNumber - closestSimTickNoLesser))
                {
                    return(new FindSnapshotResult(_snapshotRingBuffer, closestIndexGreater));
                }
                else
                {
                    return(new FindSnapshotResult(_snapshotRingBuffer, closestIndexLesser));
                }
            }
            else
            {
                return(FindSnapshotResult.NotFound);
            }
        }
예제 #13
0
 private static void CreateNewSnapshotData(
     SnapshotStore <InputSnapshotsComponent.InputCommandSet> snapshotStore,
     SimulationTickNumber simulationTickNumber,
     PlayerInputSequenceNumber nextPlayerInputSequenceNumber)
 {
     ref var inputSet = ref snapshotStore.GetOrCreate(simulationTickNumber, out bool wasCreated);
예제 #14
0
 public void SetClockFromTickNumber(SimulationTickNumber simulationTickNumber)
 {
     LastServerSimulationTickNumber = simulationTickNumber;
     CurrentTickTimeElapsed         = TimeSpan.Zero;
     TargetTotalTime = TimeSpan.FromTicks(simulationTickNumber * GameConfig.PhysicsFixedTimeStep.Ticks);
 }