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); }
internal void Copy(InputFrame other) { other.FrameNumber = FrameNumber; SWBytes.CopyFull(bytes, other.bytes); }