int Simulate(int frameNumber)
        {
            SWConsole.Crit($"Engine: Simulate frameNumber={frameNumber}");

            InputFrame lastInputFrame = inputFrames[frameNumber - 1];

            InputFrameDelta lastInputFrameDelta = inputFrameDeltas[frameNumber - 1];

            int playerFrameNumber = lastInputFrameDelta.playerFrameNumber;

            InputFrame inputFrame = inputFrames[frameNumber];

            if (inputFrame == null)
            {
                inputFrame = new InputFrame(frameNumber);
                inputFrames[frameNumber] = inputFrame;
            }

            inputFrame.FrameNumber = frameNumber;
            inputFrame.ResetBytes();

            if (lastInputFrame == null || _input == null || inputFrame == null || lastInputFrameDelta == null)
            {
                SWConsole.Error($"Engine: Simulate input data is nil {lastInputFrame} {_input} {inputFrame} {lastInputFrameDelta}");
            }

            lastInputFrameDelta.Apply(_input, lastInputFrame, inputFrame);

            FrameSyncUpdateType updateType = FrameSyncUpdateType.Normal;

            DoSimulate(updateType, inputFrame, frameNumber);

            return(playerFrameNumber);
        }
        void DoSimulate(FrameSyncUpdateType updateType, InputFrame inputFrame, int frameNumber)
        {
            //Input manager facing frame data
            _currentInputFrame = inputFrame;
            //user facing frame number
            _game.frameNumber = frameNumber;

            //hook for other external systems
            //For example, physics engine
            if (OnEngineWillSimulateEvent != null)
            {
                OnEngineWillSimulateEvent();
            }

            //seed the random number generator
            FrameSyncRandom._internal_seed((UInt32)frameNumber);

            foreach (SWFrameSyncSystem system in _systems)
            {
                system.WillUpdate();
            }

            foreach (SWFrameSyncSystem system in _systems)
            {
                system.Update(_game, _input, updateType);
            }
        }
        internal void ApplyPrediction(FrameSyncInput input, InputFrame i1, InputFrame i2)
        {
            //copy i1 to i2
            SWBytes.CopyFull(i1.bytes, i2.bytes);

            //let input reset
            //important to reset triggers
            input.InputJustCopied(i2.bytes);

            byte inputSize = input.Size;

            if (bytes.DataLength > 0)
            {
                byte playerCount = bytes.PopByte();

                for (int i = 0; i < playerCount; i++)
                {
                    byte            playerID = bytes.PopByte();
                    FrameSyncPlayer player   = input.GetPlayer(playerID);
                    byte            offset   = player.InputOffset;
                    SWBytes.Copy(bytes, i2.bytes, bytes.ReadIndex, offset, inputSize);
                    bytes.SkipRead(inputSize);
                }
            }

            //reset read index
            bytes.SetReadIndex(0);

            //prepare bitarray
            input.InputDeltaJustApplied(i2.bytes);
        }
        internal void Apply(FrameSyncInput input, InputFrame i1, InputFrame i2)
        {
            //copy i1 to i2
            SWBytes.CopyFull(i1.bytes, i2.bytes);

            //let input reset
            //important to reset triggers
            input.InputJustCopied(i2.bytes);

            //apply delta for each player
            byte inputSize = input.Size;

            SWConsole.Crit($"ApplyDelta delta frameNumber={frameNumber} {bytes.FullString()}");

            while (bytes.DataLength > 0)
            {
                byte            playerID = bytes.PopByte();
                FrameSyncPlayer player   = input.GetPlayer(playerID);
                if (player == null)
                {
                    SWConsole.Error($"InputFrameDelta Apply: player not found {playerID}");
                }
                byte offset = player.InputOffset;
                SWBytes.Copy(bytes, i2.bytes, bytes.ReadIndex, offset, inputSize);
                bytes.SkipRead(inputSize);
            }

            //reset read index
            bytes.SetReadIndex(0);

            //prepare bitarray
            input.InputDeltaJustApplied(i2.bytes);
        }
 public FrameSyncEngine()
 {
     _staticFrameSyncBehaviourManager  = new StaticFrameSyncBehaviourManager();
     _dynamicFrameSyncBehaviourManager = new DynamicFrameSyncBehaviourManager();
     _systems    = new SWFrameSyncSystem[2];
     _systems[0] = _staticFrameSyncBehaviourManager;
     _systems[1] = _dynamicFrameSyncBehaviourManager;
     _lastInputFrameForPrediction = new InputFrame();
     _inputFrameForPrediction     = new InputFrame();
 }
        void WaitingForRoomFrame()
        {
            if (_firstFrameReceived > 0)
            {
                SWConsole.Crit($"WaitingForRoomFrame _firstFrameReceived={_firstFrameReceived}");
                InputFrameDelta delta = inputFrameDeltas[_firstFrameReceived];

                if (delta != null)
                {
                    SWConsole.Crit($"WaitingForRoomFrame delta not null Delta.frameNumber = {delta.frameNumber}");
                    if (delta.frameNumber == _firstFrameReceived)
                    {
                        if (_firstFrameReceived > 1)
                        {
                            _game.gameState = FrameSyncGameState.WaitingForInitialSystemData;
                            SWConsole.Crit($"WaitingForRoomFrame RequestInputFrames end={_firstFrameReceived}");

                            _io.RequestInputFrames(1, _firstFrameReceived);
                            SWConsole.Crit($"WaitingForRoomFrame game WaitingForInitialSystemData now");
                        }
                        else
                        {
                            //start from 1st frame
                            _currentInputFrameNumber = 1;

                            //create an empty input frame to start with
                            inputFrames[_currentInputFrameNumber] = new InputFrame(_currentInputFrameNumber);
                            _game.gameState = FrameSyncGameState.Running;
                            SetSaveHandler(0);
                            SWConsole.Crit($"WaitingForRoomFrame game running now");
                        }

                        ResetTimeStamp();
                        return;
                    }
                }
            }
            if (CheckInterval(FrameSyncConstant.SERVER_FRAME_INITIALIZATION_INTERVAL))
            {
                SWBytes buffer = new SWBytes(32);

                buffer.Push(0); //frame number
                buffer.Push(0); //predict
                byte length = 0;
                buffer.Push(length);
                _io.SendInputFrameDeltas(buffer, 1, _input.Size);
            }
        }
        void WaitingForInitialSystemData()
        {
            if (HasNewInitialInputFrameDeltas())
            {
                //play all initial input frame
                SWConsole.Crit($"WaitingForInitialSystemData has initial input deltas startFrameNumber={_startFrameNumber}");
                InputFrame inputFrame1 = new InputFrame();
                InputFrame inputFrame2 = new InputFrame();

                int frameNumber = _startFrameNumber + 1; //if start number is 1 delta, we need to simulate 2 because 2 = 1 input + 1 delta
                foreach (InputFrameDelta delta in _initialInputFrameDeltas)
                {
                    inputFrame2.ResetBytes();
                    delta.Apply(_input, inputFrame1, inputFrame2);

                    FrameSyncUpdateType updateType = FrameSyncUpdateType.Restore;
                    SWConsole.Crit($"WaitingForInitialSystemData simulate {frameNumber}");

                    DoSimulate(updateType, inputFrame2, frameNumber);

                    InputFrame temp = inputFrame1;
                    inputFrame1 = inputFrame2;
                    inputFrame2 = temp;
                    frameNumber++;
                }

                //start from the last restored frame;
                frameNumber--;
                _currentInputFrameNumber = frameNumber;
                ExportSimulationResult();
                //create an empty input frame to start with
                inputFrames[frameNumber] = inputFrame1;
                //export system data
                ExportSimulationResult();
                SWConsole.Warn($"WaitingForInitialSystemData _initialInputFramesData={_initialInputFramesData.DataLength}");
                _saveHandler(_initialInputFramesData, _startFrameNumber, _endFrameNumber);
                _game.gameState = FrameSyncGameState.Running;

                SetSaveHandler(_endFrameNumber - 1); //end frame was excluded from initial frames, so we want to save it
                SWConsole.Crit($"WaitingForInitialSystemData game is running now _currentInputFrameNumber={_currentInputFrameNumber}");
                ResetTimeStamp();
                return;
            }
        }
        void InitializingRoomFrame()
        {
            if (_game.type == FrameSyncGameType.Offline)
            {
                _game.gameState = FrameSyncGameState.Running;

                _lastReceivedInputFrameDeltaNumber = int.MaxValue - 100; //a large number, -100 to make it don't overflow

                _currentInputFrameNumber = 1;

                InitializeFrames(0);
                SetSaveHandler(0);
                //create an empty input frame to start with
                //input frame delta will be created in the next FlushInput
                inputFrames[_currentInputFrameNumber] = new InputFrame(_currentInputFrameNumber);
            }
            else
            {
                _io.StartReceivingInputFrame();
                _game.gameState = FrameSyncGameState.WaitingForRoomFrame;
                ResetTimeStamp();
            }
        }
        void RunningOnlineWithPrediction()
        {
            SWConsole.Crit("Engine: ================RunningOnlineWithPrediction=================");
            //FlushInputOnlinePrediction();

            // check if we got new server frame to simulate
            int nextServerFrame = _currentInputFrameNumber + 1;

            if (true)  //CanSimulateInputFrame(nextServerFrame))
            {
                // restore the last simulated server frame before simulate any new server frame
                RestoreToConfirmedFrame();
            }

            int lastSimulatedPlayerFrameNumber = 0;

            // simulate all server frames first
            for (; nextServerFrame <= _lastReceivedInputFrameDeltaNumber + 1; nextServerFrame++)
            {
                if (CanSimulateInputFrame(nextServerFrame))
                {
                    lastSimulatedPlayerFrameNumber = SimulateInputFrame(nextServerFrame);
                    SWConsole.Crit($"lastSimulatedPlayerFrameNumber={lastSimulatedPlayerFrameNumber}");
                    if (lastSimulatedPlayerFrameNumber == 0)
                    {
                        // local player's input frame missing for this frame
                        if (_nextPlayerFrameNumberToConfirm > 1)
                        {
                            SWConsole.Warn("wtf");
                        }
                    }
                    else
                    {
                        _nextPlayerFrameNumberToConfirm = lastSimulatedPlayerFrameNumber + 1;
                        SWConsole.Crit($"nextPlayerFrameNumberToConfirm={_nextPlayerFrameNumberToConfirm}");
                    }

                    ExportSimulationResult();
                }
                else
                {
                    break;
                }
            }

            // if last simulated server frame has local player's input
            // we should simulate all player's input frames after it
            if (true)  // lastSimulatedPlayerFrameNumber > 0)
            {
                InputFrame lastInputFrame = inputFrames[nextServerFrame - 1];
                lastInputFrame.Copy(_lastInputFrameForPrediction);
                int startPlayerFrameNumber = _nextPlayerFrameNumberToConfirm;

                int endPlayerFrameNumber = _currentLocalInputFrameDeltaNumber - FrameSyncConstant.PREDICTION_GLOBAL_DEBAY_FRAMES;

                int predictFrameNumber = nextServerFrame;

                SWConsole.Crit($"startPlayerFrameNumber={startPlayerFrameNumber}");
                SWConsole.Crit($"endPlayerFrameNumber={endPlayerFrameNumber}");
                // endPlayerFrameNumber + 1 to include the endPlayerFrameNumber
                for (int i = startPlayerFrameNumber; i < endPlayerFrameNumber + 1; i++)
                {
                    Predict(i, predictFrameNumber);
                    predictFrameNumber++;

                    //swap prediction InputFrames for the next prediction
                    InputFrame temp = _lastInputFrameForPrediction;
                    _lastInputFrameForPrediction = _inputFrameForPrediction;
                    _inputFrameForPrediction     = temp;
                }
            }

            //reset game.frameNumber to the last confirmed frame
            //this is for debug server
            _game.frameNumber = _currentInputFrameNumber;

            SWConsole.Crit("Engine: ================end=================");
        }
        //Debug
        public InputFrame GetInputFrame(int frameNumber)
        {
            InputFrame inputFrame = inputFrames[frameNumber];

            return(inputFrame);
        }
Beispiel #11
0
 internal void Copy(InputFrame other)
 {
     other.FrameNumber = FrameNumber;
     SWBytes.CopyFull(bytes, other.bytes);
 }