Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replacing code with the TryToFix branch / Removed InputAckedFrame message #3

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 8 additions & 17 deletions src/input/InputQueue.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Diagnostics;

namespace PleaseResync
Expand All @@ -6,29 +7,22 @@ internal class InputQueue
{
public const int QueueSize = 128;
private uint _frameDelay;
private uint _inputSize;
private uint _playerCount;
private GameInput[] _inputs;
private GameInput[] _lastPredictedInputs;

public InputQueue(uint inputSize, uint playerCount, uint frameDelay = 0)
{
_inputSize = inputSize;
_frameDelay = frameDelay;
_playerCount = playerCount;
_inputs = new GameInput[QueueSize];
_lastPredictedInputs = new GameInput[QueueSize];

for (int i = 0; i < _inputs.Length; i++)
{
_inputs[i] = EmptyInput();
_lastPredictedInputs[i] = EmptyInput();
_inputs[i] = new GameInput(GameInput.NullFrame, inputSize, playerCount);
_lastPredictedInputs[i] = new GameInput(GameInput.NullFrame, inputSize, playerCount);
}
}
public GameInput EmptyInput()
{
return new GameInput(GameInput.NullFrame, _inputSize, _playerCount);
}

public GameInput GetPredictedInput(int frame)
{
return _lastPredictedInputs[frame % QueueSize];
Expand Down Expand Up @@ -70,16 +64,13 @@ public GameInput GetInput(int frame, bool predict = true)
return new GameInput(_inputs[frameOffset]);
}

public void ResetPredictions()
public void ResetPrediction(int frame)
{
// when resetting the prediction we just make the frame a null frame.
// TODO MAKE A BETTER PREDDICTION SYSTEM.
for (int i = 0; i < QueueSize; i++)
{
_lastPredictedInputs[i].Frame = GameInput.NullFrame;
}
int frameOffset = frame % QueueSize;
_lastPredictedInputs[frameOffset].Frame = GameInput.NullFrame;
}

private int PreviousFrame(int offset) => (((offset) == 0) ? (QueueSize - 1) : ((offset) - 1));
}
}
}
5 changes: 3 additions & 2 deletions src/session/Device.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void FinishedSyncing()
{
State = DeviceState.Running;
var ev = new DeviceSyncedEvent { DeviceId = Id };
_session.AddSessionEvent(ev);
//_session.AddSessionEvent(ev);
}

#endregion
Expand Down Expand Up @@ -140,9 +140,10 @@ public void HandleMessage(DeviceMessage message)
break;
case DeviceInputMessage inputMessage:
_session.AddRemoteInput(Id, inputMessage);
LastAckedInputFrame = inputMessage.EndFrame; //Getting the acked frame from the input message
break;
case DeviceInputAckMessage inputAckMessage:
UpdateAckedInputFrame(inputAckMessage);
//UpdateAckedInputFrame(inputAckMessage); //Removed for now
break;
}
}
Expand Down
12 changes: 3 additions & 9 deletions src/session/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,6 @@ public Session(uint inputSize, uint deviceCount, uint totalPlayerCount)
/// </summary>
public abstract void Poll();
/// <summary>
/// Returns a queue with all the events that happend since the last call to this function.
/// <summary>
public abstract Queue<SessionEvent> Events();
/// <summary>
/// IsRunning returns true when all the Sessions are synchronized and ready to accept inputs.
/// </summary>
public abstract bool IsRunning();
Expand All @@ -97,9 +93,7 @@ public Session(uint inputSize, uint deviceCount, uint totalPlayerCount)
/// <param name="localInput">the local device input for the current frame</param>
/// <returns>a list of actions to perform in order before calling AdvanceFrame again</returns>
public abstract List<SessionAction> AdvanceFrame(byte[] localInput);

protected internal abstract uint SendMessageTo(uint deviceId, DeviceMessage message);
protected internal abstract void AddRemoteInput(uint deviceId, DeviceInputMessage message);
protected internal abstract void AddSessionEvent(SessionEvent ev);
internal protected abstract uint SendMessageTo(uint deviceId, DeviceMessage message);
internal protected abstract void AddRemoteInput(uint deviceId, DeviceInputMessage message);
}
}
}
80 changes: 5 additions & 75 deletions src/session/backends/Peer2PeerSession.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using System;

namespace PleaseResync
{
Expand All @@ -19,18 +18,11 @@ public class Peer2PeerSession : Session
private Sync _sync;
private Device _localDevice;

// events
private const int MinSuggestionTime = 3;
private Queue<SessionEvent> _sessionEvents;
private int _nextSuggestedWait;

public Peer2PeerSession(uint inputSize, uint deviceCount, uint totalPlayerCount, SessionAdapter adapter) : base(inputSize, deviceCount, totalPlayerCount)
{
_allDevices = new Device[deviceCount];
_sessionAdapter = adapter;
_sync = new Sync(_allDevices, inputSize);
_nextSuggestedWait = 0;
_sessionEvents = new Queue<SessionEvent>(32);
}

public override void SetLocalDevice(uint deviceId, uint playerCount, uint frameDelay)
Expand Down Expand Up @@ -84,71 +76,19 @@ public override bool IsRunning()
public override List<SessionAction> AdvanceFrame(byte[] localInput)
{
Debug.Assert(IsRunning(), "Session must be running before calling AdvanceFrame");

// should be called after polling the remote devices for their messages.
Debug.Assert(localInput != null);

var actions = new List<SessionAction>();

// create savestate at the initialFrame to support rolling back to it
// for example if initframe = 0 then 0 will be first save option to rollback to.
if (_sync.LocalFrame() == TimeSync.InitialFrame)
{
actions.Add(new SessionSaveGameAction(_sync.LocalFrame(), _sync.StateStorage()));
}

// update time sync variables
_sync.UpdateTimeSync();

// find the first frame where you have all correct inputs of all devices
_sync.UpdateSyncFrame();

// rollback update
if (_sync.ShouldRollback())
{
actions.Add(new SessionLoadGameAction(_sync.SyncFrame(), _sync.StateStorage()));
for (int i = _sync.SyncFrame() + 1; i <= _sync.LocalFrame(); i++)
{
actions.Add(new SessionAdvanceFrameAction(i, _sync.GetFrameInput(i).Inputs));
actions.Add(new SessionSaveGameAction(i, _sync.StateStorage())); //? later add an less intensive save method? saving every frame might not be needed.
}
}

// normal update
_sync.IncrementFrame();

_sync.AddLocalInput(LocalDevice.Id, localInput);

var game = _sync.GetFrameInput(_sync.LocalFrame());

actions.Add(new SessionAdvanceFrameAction(_sync.LocalFrame(), game.Inputs));
actions.Add(new SessionSaveGameAction(_sync.LocalFrame(), _sync.StateStorage()));

//send inputs to remote devices
_sync.SendLocalInputs(LocalDevice.Id);

CheckWaitSuggestion();

return actions;
Poll();
return _sync.AdvanceSync(_localDevice.Id, localInput);
}

private void CheckWaitSuggestion()
{
if (_sync.LocalFrame() > _nextSuggestedWait && _sync.FrameAdvantage() >= MinSuggestionTime)
{
_nextSuggestedWait = _sync.LocalFrame() + MinSuggestionTime;
var suggestedWait = new WaitSuggestionEvent { Frames = (uint)_sync.FrameAdvantage() };
AddSessionEvent(suggestedWait);
}
}

protected internal override uint SendMessageTo(uint deviceId, DeviceMessage message)
internal protected override uint SendMessageTo(uint deviceId, DeviceMessage message)
{
System.Console.WriteLine($"Sending message to remote device {deviceId}: {message}");
return _sessionAdapter.SendTo(deviceId, message);
}

protected internal override void AddRemoteInput(uint deviceId, DeviceInputMessage message)
internal protected override void AddRemoteInput(uint deviceId, DeviceInputMessage message)
{

uint inputCount = (message.EndFrame - message.StartFrame) + 1;
Expand All @@ -167,15 +107,5 @@ protected internal override void AddRemoteInput(uint deviceId, DeviceInputMessag
inputIndex++;
}
}

public override Queue<SessionEvent> Events()
{
return _sessionEvents;
}

protected internal override void AddSessionEvent(SessionEvent ev)
{
_sessionEvents.Enqueue(ev);
}
}
}
}
74 changes: 53 additions & 21 deletions src/synchronization/Sync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,17 @@ public void AddRemoteInput(uint deviceId, int frame, byte[] deviceInput)
{
_devices[deviceId].RemoteFrame = frame;
_devices[deviceId].RemoteFrameAdvantage = _timeSync.LocalFrame - frame;
// let them know u recieved the packet
_devices[deviceId].SendMessage(new DeviceInputAckMessage { Frame = (uint)frame });
}
// let them know u recieved the packet
_devices[deviceId].SendMessage(new DeviceInputAckMessage { Frame = (uint)frame });
AddDeviceInput(frame, deviceId, deviceInput);
}

public uint FramesAhead()
{
return (uint)_timeSync.LocalFrameAdvantage;
}

public void SetLocalDevice(uint deviceId, uint playerCount, uint frameDelay)
{
_deviceInputs[deviceId] = new InputQueue(_inputSize, playerCount, frameDelay);
Expand All @@ -47,13 +52,50 @@ public void AddRemoteDevice(uint deviceId, uint playerCount)
_deviceInputs[deviceId] = new InputQueue(_inputSize, playerCount);
}

public void UpdateTimeSync() => _timeSync.UpdateTimeSync(_devices);
public List<SessionAction> AdvanceSync(uint localDeviceId, byte[] deviceInput)
{
// should be called after polling the remote devices for their messages.
Debug.Assert(deviceInput != null);

public int LocalFrame() => _timeSync.LocalFrame;
bool isTimeSynced = _timeSync.IsTimeSynced(_devices);

public void IncrementFrame() => _timeSync.LocalFrame++;
UpdateSyncFrame();

var actions = new List<SessionAction>();

// create savestate at the initialFrame to support rolling back to it
// for example if initframe = 0 then 0 will be first save option to rollback to.
if (_timeSync.LocalFrame == TimeSync.InitialFrame)
{
actions.Add(new SessionSaveGameAction(_timeSync.LocalFrame, _stateStorage));
}

// rollback update
if (_timeSync.ShouldRollback())
{
actions.Add(new SessionLoadGameAction(_timeSync.SyncFrame, _stateStorage));
for (int i = _timeSync.SyncFrame + 1; i <= _timeSync.LocalFrame; i++)
{
actions.Add(new SessionAdvanceFrameAction(i, GetFrameInput(i).Inputs));
actions.Add(new SessionSaveGameAction(i, _stateStorage));
}
}

public void SendLocalInputs(uint localDeviceId)
if (isTimeSynced)
{
_timeSync.LocalFrame++;

AddLocalInput(localDeviceId, deviceInput);
SendLocalInputs(localDeviceId);

actions.Add(new SessionAdvanceFrameAction(_timeSync.LocalFrame, GetFrameInput(_timeSync.LocalFrame).Inputs));
actions.Add(new SessionSaveGameAction(_timeSync.LocalFrame, _stateStorage));
}

return actions;
}

private void SendLocalInputs(uint localDeviceId)
{
foreach (var device in _devices)
{
Expand All @@ -78,13 +120,7 @@ public void SendLocalInputs(uint localDeviceId)
}
}

public StateStorage StateStorage() => _stateStorage;

public bool ShouldRollback() => _timeSync.ShouldRollback();

public int SyncFrame() => _timeSync.SyncFrame;

public void UpdateSyncFrame()
private void UpdateSyncFrame()
{
int finalFrame = _timeSync.RemoteFrame;
if (_timeSync.RemoteFrame > _timeSync.LocalFrame)
Expand All @@ -108,23 +144,21 @@ public void UpdateSyncFrame()
foundMistake = true;
}
// remove prediction form queue
input.ResetPredictions();
input.ResetPrediction(i);
}
}
if (foundMistake) break;
}
_timeSync.SyncFrame = foundFrame;
}

public void AddLocalInput(uint deviceId, byte[] deviceInput)
private void AddLocalInput(uint deviceId, byte[] deviceInput)
{
// only allow adding input to the local device
Debug.Assert(_devices[deviceId].Type == Device.DeviceType.Local);
// check if the predictition threshold has been reached.
Debug.Assert(_timeSync.PredictionLimitReached() == false, "Prediction Limit Reached!");
AddDeviceInput(_timeSync.LocalFrame, deviceId, deviceInput);
}

private void AddDeviceInput(int frame, uint deviceId, byte[] deviceInput)
{
Debug.Assert(deviceInput.Length == _devices[deviceId].PlayerCount * _inputSize,
Expand Down Expand Up @@ -162,7 +196,5 @@ public GameInput GetFrameInput(int frame)
}
return input;
}

public int FrameAdvantage() => _timeSync.FrameAdvantage;
}
}
}
Loading
Loading