public bool AddLocalInput(int queue, ref GameInput input) { int framesBehind = FrameCount - lastConfirmedFrame; if (FrameCount >= maxPredictionFrames && framesBehind >= maxPredictionFrames) { Log("Rejecting input from emulator: reached prediction barrier."); return(false); } if (FrameCount == 0) { SaveCurrentFrame(); } Log($"Sending undelayed local frame {FrameCount} to queue {queue}."); input.frame = FrameCount; inputQueues[queue].AddInput(ref input); return(true); }
public int SyncrhonizeInputs(ref byte[] values) { int disconnect_flags = 0; Debug.Assert(values.Length >= config.numPlayers * config.inputSize); Unsafe.InitBlock(ref values[0], 0, (uint)values.Length); for (int i = 0; i < config.numPlayers; i++) { var input = new GameInput(GameInput.NullFrame, null, (uint)config.inputSize); if (localConnectStatus[i].Disconnected && FrameCount > localConnectStatus[i].LastFrame) { disconnect_flags |= (1 << i); } else { inputQueues[i].GetInput(FrameCount, ref input); } Unsafe.CopyBlock(ref values[i * config.inputSize], ref input.bits[0], (uint)config.inputSize); } return(disconnect_flags); }
public void AddInput(ref GameInput input) { int newFrame; Log($"adding input frame number {input.frame} to queue."); // These next two lines simply verify that inputs are passed in // sequentially by the user, regardless of frame delay. Debug.Assert(lastUserAddedFrame == GameInput.NullFrame || input.frame == lastUserAddedFrame + 1); lastUserAddedFrame = input.frame; // Move the queue head to the correct point in preparation to // input the frame into the queue. newFrame = AdvanceQueueHead(input.frame); if (newFrame != GameInput.NullFrame) { AddDelayedInputToQueue(ref input, newFrame); } // Update the frame number for the input. This will also set the // frame to GameInput::NullFrame for frames that get dropped (by // design). input.frame = newFrame; }
public bool GetInput(int requestedFrame, ref GameInput input) { Log($"requesting input frame {requestedFrame}."); // No one should ever try to grab any input when we have a prediction // error. Doing so means that we're just going further down the wrong // path. ASSERT this to verify that it's true. Debug.Assert(firstIncorrectFrame == GameInput.NullFrame); // Remember the last requested frame number for later. We'll need // this in AddInput() to drop out of prediction mode. lastFrameRequested = requestedFrame; Debug.Assert(requestedFrame >= inputs[tail].frame); if (prediction.frame == GameInput.NullFrame) { // If the frame requested is in our range, fetch it out of the queue and // return it. int offset = requestedFrame - inputs[tail].frame; if (offset < length) { offset = (offset + tail) % inputs.Length; Debug.Assert(inputs[offset].frame == requestedFrame); input = inputs[offset]; Log($"returning confirmed frame number {input.frame}."); return(true); } // The requested frame isn't in the queue. Bummer. This means we need // to return a prediction frame. Predict that the user will do the // same thing they did last time. if (requestedFrame == 0) { Log("basing new prediction frame from nothing, you're client wants frame 0."); prediction.Erase(); } else if (lastAddedFrame == GameInput.NullFrame) { Log("basing new prediction frame from nothing, since we have no frames yet."); prediction.Erase(); } else { Log($"basing new prediction frame from previously added frame (queue entry:{PreviousFrame(head)}, frame:{inputs[PreviousFrame(head)].frame})."); prediction = inputs[PreviousFrame(head)]; } prediction.frame++; } Debug.Assert(prediction.frame >= 0); // If we've made it this far, we must be predicting. Go ahead and // forward the prediction frame contents. Be sure to return the // frame number requested by the client, though. input = prediction; input.frame = requestedFrame; Log($"returning prediction frame number {input.frame} ({prediction.frame})."); return(false); }
public void AddRemoteInput(int queue, ref GameInput input) { inputQueues[queue].AddInput(ref input); }