Skip to content
This repository has been archived by the owner on Nov 16, 2022. It is now read-only.

Fixing initialization errors and unity log errors. Also fixes a bug with int encoding of the frames in backroll connection. #5

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
147 changes: 82 additions & 65 deletions Runtime/Backends/P2PBackrollSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,6 @@ public unsafe class P2PBackrollSession<T> : BackrollSession<T> where T : struct
BackrollSessionCallbacks _callbacks;
Sync _sync;

public bool IsSynchronizing {
get {
for (var i = 0; i < _players.Length; i++) {
if (!_players[i].IsLocal && !_players[i].IsSynchronized &&
!_localConnectStatus[i].Disconnected) {
return false;
}
}
for (var i = 0; i < _spectators.Length; i++) {
if (!_spectators[i].IsLocal && !_spectators[i].IsSynchronized) {
return false;
}
}
return true;
}
}

int _next_recommended_sleep;
int _next_spectator_frame;

Expand All @@ -76,37 +59,46 @@ public P2PBackrollSession(BackrollSessionConfig config) {

_callbacks = config.Callbacks;

_players = InitializeConnections(config.Players);
_spectators = InitializeConnections(config.Spectators);

_localConnectStatus = new BackrollConnectStatus[PlayerCount];
for (int i = 0; i < _localConnectStatus.Length; i++) {
_localConnectStatus[i].LastFrame = -1;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this initialization change do? What was broken before?

Copy link

@christopherliu830 christopherliu830 Jan 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous code checked PlayerCount on line 87 (_players.Length) before _players was assigned (line 94)
also, SetupConnection tries to get the index of the player in _players so it can't be used during the assignment to _players

SetupConnections(_players);
SetupConnections(_spectators);

// Initialize the synchronziation layer
_sync = new Sync(_localConnectStatus, new Sync.Config {
NumPlayers = config.Players.Length,
InputSize = InputSize,
Callbacks = _callbacks,
NumPredictionFrames = BackrollConstants.kMaxPredictionFrames,
});

_localConnectStatus = new BackrollConnectStatus[PlayerCount];
for (int i = 0; i < _localConnectStatus.Length; i++) {
unchecked {
_localConnectStatus[i].LastFrame = ~0;
}
}

_players = InitializeConnections(config.Players);
_spectators = InitializeConnections(config.Spectators);

}

BackrollConnection[] InitializeConnections(LobbyMember[] members) {
Assert.IsNotNull(members);
var connections = new BackrollConnection[members.Length];
for (var i = 0; i < connections.Length; i++) {
var connection = new BackrollConnection(members[i], i, _localConnectStatus);
connections[i] = connection;
}
return connections;
}

void SetupConnections(BackrollConnection[] connections) {
for (var i = 0; i < connections.Length; i++) {
ref BackrollConnection connection = ref connections[i];
SetupConnection(connection);
connection.SetDisconnectTimeout((uint)DEFAULT_DISCONNECT_TIMEOUT);
connection.SetDisconnectNotifyStart((uint)DEFAULT_DISCONNECT_NOTIFY_START);
connection.Synchronize();
connections[i] = connection;
}
return connections;
}

void UpdateConnections() {
Expand All @@ -119,7 +111,8 @@ void UpdateConnections() {
}

public override void Idle(int timeout) {
if (_sync.InRollback || IsSynchronizing) return;

if (_sync.InRollback) return;
UpdateConnections();
_sync.CheckSimulation(timeout);

Expand All @@ -137,12 +130,12 @@ public override void Idle(int timeout) {
minFrame = PollNPlayers(current_frame);
}

Debug.LogFormat("last confirmed frame in p2p backend is {}.", minFrame);
if (Backroll.LOG_BACKROLL) Debug.LogFormat("last confirmed frame in p2p backend is {0}.", minFrame);
if (minFrame >= 0) {
Assert.IsTrue(minFrame != int.MaxValue);
if (SpectatorCount > 0) {
while (_next_spectator_frame <= minFrame) {
Debug.LogFormat("pushing frame {} to spectators.", _next_spectator_frame);
if (Backroll.LOG_BACKROLL) Debug.LogFormat("pushing frame {0} to spectators.", _next_spectator_frame);

GameInput input;
input.Frame = _next_spectator_frame;
Expand All @@ -154,7 +147,7 @@ public override void Idle(int timeout) {
_next_spectator_frame++;
}
}
Debug.LogFormat("setting confirmed frame in sync to {}.", minFrame);
if (Backroll.LOG_BACKROLL) Debug.LogFormat("setting confirmed frame in sync to {0}.", minFrame);
_sync.SetLastConfirmedFrame(minFrame);
}

Expand Down Expand Up @@ -185,17 +178,18 @@ protected int Poll2Players(int current_frame) {
int ignore = 0;
connected = _players[i].GetPeerConnectStatus(i, ref ignore);
}

if (!_localConnectStatus[i].Disconnected) {
minFrame = (int)Math.Min(_localConnectStatus[i].LastFrame, minFrame);
}
Debug.LogFormat(" local endp: connected = {}, last_received = {}, minFrame = {}.",
if (Backroll.LOG_BACKROLL) Debug.LogFormat(" local endp: connected = {0}, last_received = {1}, minFrame = {2}.",
!_localConnectStatus[i].Disconnected, _localConnectStatus[i].LastFrame,
minFrame);
if (!connected && !_localConnectStatus[i].Disconnected) {
Debug.LogFormat("disconnecting i {} by remote request.", i);
Debug.LogFormat("disconnecting i {0} by remote request.", i);
DisconnectPlayerQueue(i, minFrame);
}
Debug.LogFormat(" minFrame = {}.", minFrame);
if (Backroll.LOG_BACKROLL) Debug.LogFormat(" minFrame = {0}.", minFrame);
}
return minFrame;
}
Expand All @@ -208,7 +202,7 @@ protected int PollNPlayers(int current_frame) {
for (var queue = 0; queue < PlayerCount; queue++) {
bool connected = true;
int minConfirmed = Int32.MaxValue;
Debug.LogFormat("considering queue {}.", queue);
if (Backroll.LOG_BACKROLL) Debug.LogFormat("considering queue {0}.", queue);
for (var i = 0; i < _players.Length; i++) {
// we're going to do a lot of logic here in consideration of endpoint i.
// keep accumulating the minimum confirmed point for all n*n packets and
Expand All @@ -217,17 +211,17 @@ protected int PollNPlayers(int current_frame) {
bool peer_connected = _players[i].GetPeerConnectStatus(queue, ref last_received);
connected = connected && peer_connected;
minConfirmed = Mathf.Min(last_received, minConfirmed);
Debug.Log(
if (Backroll.LOG_BACKROLL) Debug.Log(
$" endpoint {i}: connected = {connected}, last_received = {last_received}, minConfirmed = {minConfirmed}.");
} else {
Debug.Log($" endpoint {i}: ignoring... not running.");
if (Backroll.LOG_BACKROLL) Debug.Log($" endpoint {i}: ignoring... not running.");
}
}
// merge in our local status only if we're still connected!
if (!_localConnectStatus[queue].Disconnected) {
minConfirmed = (int)Math.Min(_localConnectStatus[queue].LastFrame, minConfirmed);
}
Debug.LogFormat(" local endp: connected = {}, last_received = {}, minConfirmed = {}.",
if (Backroll.LOG_BACKROLL) Debug.LogFormat(" local endp: connected = {0}, last_received = {1}, minConfirmed = {2}.",
!_localConnectStatus[queue].Disconnected, _localConnectStatus[queue].LastFrame, minConfirmed);

if (connected) {
Expand All @@ -237,11 +231,11 @@ protected int PollNPlayers(int current_frame) {
// so, we need to re-adjust. This can happen when we detect our own disconnect at frame n
// and later receive a disconnect notification for frame n-1.
if (!_localConnectStatus[queue].Disconnected || _localConnectStatus[queue].LastFrame > minConfirmed) {
Debug.LogFormat("disconnecting queue {} by remote request.", queue);
if (Backroll.LOG_BACKROLL) Debug.LogFormat("disconnecting queue {0} by remote request.", queue);
DisconnectPlayerQueue(queue, minConfirmed);
}
}
Debug.LogFormat(" minFrame = {}.", minFrame);
if (Backroll.LOG_BACKROLL) Debug.LogFormat(" minFrame = {0}.", minFrame);
}
return minFrame;
}
Expand All @@ -252,17 +246,18 @@ public override void AddLocalInput(BackrollPlayerHandle player,
GameInput input;

if (_sync.InRollback) {
// Debug.Log("BackrollException: InRollback");
// return;
throw new BackrollException(BackrollErrorCode.InRollback);
}
if (IsSynchronizing) {
throw new BackrollException(BackrollErrorCode.NotSynchronized);
}

queue = PlayerHandleToQueue(player);
input = GameInput.Create<T>(GameInput.kNullFrame, ref playerInput);

// Feed the input for the current frame into the synchronzation layer.
if (!_sync.AddLocalInput(queue, ref input)) {
// Debug.Log("BackrollException PredictionThreshold");
// return;
throw new BackrollException(BackrollErrorCode.PredictionThreshold);
}

Expand All @@ -272,7 +267,7 @@ public override void AddLocalInput(BackrollPlayerHandle player,
// confirmed local frame for this player. this must come first so it
// gets incorporated into the next packet we send.

Debug.LogFormat("setting local connect status for local queue {} to {}",
if (Backroll.LOG_BACKROLL) Debug.LogFormat("setting local connect status for local queue {0} to {1}",
queue, input.Frame);
_localConnectStatus[queue].LastFrame = input.Frame;

Expand All @@ -286,14 +281,11 @@ public override void AddLocalInput(BackrollPlayerHandle player,

public override int SyncInput(void *values, int size) {
// Wait until we've started to return inputs.
if (IsSynchronizing) {
throw new BackrollException(BackrollErrorCode.NotSynchronized);
}
return _sync.SynchronizeInputs(values, size);
}

public override void AdvanceFrame() {
Debug.LogFormat("End of frame ({})...", _sync.FrameCount);
if (Backroll.LOG_BACKROLL) Debug.LogFormat("End of frame ({0})...", _sync.FrameCount);
_sync.IncrementFrame();
Idle(0);
}
Expand All @@ -310,28 +302,46 @@ static int GetIndex(INetworkReciever reciever, BackrollConnection[] connections)
void SetupConnection(BackrollConnection connection) {
var member = connection.LobbyMember;
var queue = GetIndex(connection.LobbyMember, _players);
member.OnDisconnected += () => {
if (queue >= 0) {
DisconnectPlayer(QueueToPlayerHandle(queue));
}
var spectator = GetIndex(member, _spectators);
if (spectator >= 0) {
_spectators[spectator].Disconnect();
}
};

Action action = new Action(() =>
{
if (queue >= 0)
{
try
{
DisconnectPlayer(QueueToPlayerHandle(queue));
}
catch (BackrollException e)
{
Debug.Log(e.Message);
}

}
var spectator = GetIndex(member, _spectators);
if (spectator >= 0)
{
_spectators[spectator].Disconnect();
}
});
member.OnDisconnected += action;

if (queue < 0) return ;
var handle = QueueToPlayerHandle(queue);
connection.OnInput += (input) => {
if (_localConnectStatus[queue].Disconnected) return;
int current_remote_frame = _localConnectStatus[queue].LastFrame;
int new_remote_frame = input.Frame;

if (Backroll.LOG_BACKROLL) Debug.Log($"[BackrollConnection][Nibblet][Read] Use Me! Remote Frame {new_remote_frame}, Last Frame {current_remote_frame}");
Assert.IsTrue(current_remote_frame == -1 || new_remote_frame == (current_remote_frame + 1));

_sync.AddRemoteInput(queue, ref input);
// Notify the other endpoints which frame we received from a peer
Debug.LogFormat("setting remote connect status for queue {} to {}",
if (Backroll.LOG_BACKROLL) Debug.LogFormat("setting remote connect status for queue {0} to {1}",
queue, new_remote_frame);
_localConnectStatus[queue].LastFrame = new_remote_frame;

if (Backroll.LOG_BACKROLL) Debug.Log($"[BackrollConnection][Nibblet][Read] Use Me! New Remote Frame {_localConnectStatus[queue].LastFrame}");
};

connection.OnSynchronizing += (total, count) => {
Expand Down Expand Up @@ -367,24 +377,29 @@ void SetupConnection(BackrollConnection connection) {
// blob in every endpoint periodically.
public override void DisconnectPlayer(BackrollPlayerHandle player) {
int queue = PlayerHandleToQueue(player);

if (_localConnectStatus[queue].Disconnected) {
throw new BackrollException(BackrollErrorCode.PlayerDisconnected);
// Note that throwing error code will pause execution. Have to make sure that
// Debug.Log("BackrollException: Player Disconnected");
// return;
// I re-enabled the exception after adding a try catch in other parts of the code.
// Note that any exception occuring is not good and something we need to make sure we either fix or
// handle since it might have weird issues.
throw new BackrollException(BackrollErrorCode.PlayerDisconnected);
}

if (_players[queue].IsLocal) {
int current_frame = _sync.FrameCount;
// xxx: we should be tracking who the local player is, but for now assume
// that if the endpoint is not initalized, this must be the local player.
Debug.LogFormat("Disconnecting local player {} at frame {} by user request.",
Debug.LogFormat("Disconnecting local player {0} at frame {1} by user request.",
queue, _localConnectStatus[queue].LastFrame);
for (int i = 0; i < PlayerCount; i++) {
if (!_players[i].IsLocal) {
DisconnectPlayerQueue(i, current_frame);
}
}
} else {
Debug.LogFormat("Disconnecting queue {} at frame {} by user request.",
Debug.LogFormat("Disconnecting queue {0} at frame {1} by user request.",
queue, _localConnectStatus[queue].LastFrame);
DisconnectPlayerQueue(queue, _localConnectStatus[queue].LastFrame);
}
Expand All @@ -395,14 +410,14 @@ protected void DisconnectPlayerQueue(int queue, int syncto) {

_players[queue].Disconnect();

Debug.LogFormat("Changing queue {} local connect status for last frame from {} to {} on disconnect request (current: {}).",
Debug.LogFormat("Changing queue {0} local connect status for last frame from {1} to {2} on disconnect request (current: {3}).",
queue, _localConnectStatus[queue].LastFrame, syncto, framecount);

_localConnectStatus[queue].Disconnected = true;
_localConnectStatus[queue].LastFrame = syncto;

if (syncto < framecount) {
Debug.LogFormat("adjusting simulation to account for the fact that {} Disconnected @ {}.", queue, syncto);
Debug.LogFormat("adjusting simulation to account for the fact that {0} Disconnected @ {1}.", queue, syncto);
_sync.AdjustSimulation(syncto);
Debug.LogFormat("finished adjusting simulation.");
}
Expand Down Expand Up @@ -435,6 +450,8 @@ public override void SetDisconnectNotifyStart(int disconnect_notify_start) {
protected int PlayerHandleToQueue(BackrollPlayerHandle player) {
int offset = ((int)player.Id - 1);
if (offset < 0 || offset >= PlayerCount) {
// Debug.Log("BackrollException InvalidPlayerHandle");
// return offset;
throw new BackrollException(BackrollErrorCode.InvalidPlayerHandle);
}
return offset;
Expand Down
Loading