/// <summary> /// Initialize the vector war game. This initializes the game state and /// the video renderer and creates a new network session. /// </summary> /// <param name="localPort"></param> /// <param name="numPlayers"></param> /// <param name="players"></param> /// <param name="numSpectators"></param> public void Init(int localPort, int numPlayers, GGPOPlayer[] players, int numSpectators) { // Initialize the game state InitializeGameState(numPlayers); //ggpo = new PeerToPeerBackend(this, new ConsoleLogger(), localPort, numPlayers, 4); ggpo = new PeerToPeerBackend(this, new RollingBufferFileLogger("vectorwar"), localPort, numPlayers, 4); // automatically disconnect clients after 3000 ms and start our count-down timer // for disconnects after 1000 ms. To completely disable disconnects, simply use // a value of 0 for ggpo_set_disconnect_timeout. ggpo.SetDisconnectTimeout(3000); ggpo.SetDisconnectNotifyStart(1000); for (int i = 0; i < numPlayers + numSpectators; i++) { ggpo.AddPlayer(players[i], out int playerHandle); ngs.players[i].playerHandle = playerHandle; ngs.players[i].type = players[i].type; if (players[i].type == GGPOPlayerType.Local) { ngs.players[i].connectProgress = 100; ngs.LocalPlayerHandle = playerHandle; ngs.SetConnectState(playerHandle, PlayerConnectState.Connecting); ggpo.SetFrameDelay(playerHandle, Constants.FrameDelay); } else { ngs.players[i].connectProgress = 0; } } lblStatus.Text = "Connecting to peers."; Task.Factory.StartNew(() => HandleApplicationIdle(this, ggpo), TaskCreationOptions.LongRunning); }
public void Update(GGPOSession ggpo, int[] players, int numPlayers) { var stats = new GGPONetworkStats(); int i = 0; this.numPlayers = numPlayers; if (graphSize < MaxGraphSize) { i = graphSize++; } else { i = firstGraphIndex; firstGraphIndex = (firstGraphIndex + 1) % MaxGraphSize; } for (int j = 0; j < numPlayers; j++) { ggpo.GetNetworkStats(players[j], out stats); // Ping pingGraph[j][i] = (int)stats.Ping; // Frame Advantage localFairnessGraph[j][i] = stats.LocalFramesBehind; remoteFairnessGraph[j][i] = stats.RemoteFramesBehind; if (stats.LocalFramesBehind < 0 && stats.RemoteFramesBehind < 0) { // Both think it's unfair (which, ironically, is fair). Scale both and subtrace. fairnessGraph[i] = Math.Abs(Math.Abs(stats.LocalFramesBehind) - Math.Abs(stats.RemoteFramesBehind)); } else if (stats.LocalFramesBehind > 0 && stats.RemoteFramesBehind > 0) { // Impossible! Unless the network has negative transmit time. Odd.... fairnessGraph[i] = 0; } else { // They disagree. Add. fairnessGraph[i] = Math.Abs(stats.LocalFramesBehind) + Math.Abs(stats.RemoteFramesBehind); } } long now = Utility.GetCurrentTime(); if (now > lastTextUpdateTime + 500) { lblNetworkLag.Text = $"{stats.Ping} ms"; lblFrameLag.Text = $"{stats.Ping * 60 / 1000f:F1}"; lblBandwidth.Text = $"{stats.KbpsSent / 8f:F2} kilobytes/sec"; lblLocalAhead.Text = $"{stats.LocalFramesBehind} frames"; lblRemoteAhead.Text = $"{stats.RemoteFramesBehind} frames"; lastTextUpdateTime = now; } }
/// <summary> /// Create a new spectator session. /// </summary> /// <param name="localPort"></param> /// <param name="numPlayers"></param> /// <param name="hostIp"></param> /// <param name="hostPort"></param> public void InitSpectator(int localPort, int numPlayers, string hostIp, int hostPort) { // Initialize the game state InitializeGameState(numPlayers); //ggpo = new SpectatorBackend(this, new ConsoleLogger(), localPort, numPlayers, 4, hostIp, hostPort); ggpo = new SpectatorBackend(this, new RollingBufferFileLogger("vectorwar"), localPort, numPlayers, 4, hostIp, hostPort); lblStatus.Text = "Starting new spectator session"; Task.Factory.StartNew(() => HandleApplicationIdle(this, ggpo), TaskCreationOptions.LongRunning); }
/// <summary> /// Runs the game loop inside the form. /// </summary> async Task HandleApplicationIdle(VectorWar form, GGPOSession ggpo) { while (true) { while (IsApplicationIdle()) { now = Utility.GetCurrentTime(); await(Task) form.Invoke((TaskMethodInvoker) delegate { ggpo.Idle((int)Math.Max(0, next - now - 1)); return(Task.CompletedTask); }); if (now >= next) { await(Task) form.Invoke((TaskMethodInvoker) delegate { GameUpdate(); return(Task.CompletedTask); }); await(Task) form.Invoke((TaskMethodInvoker) delegate { Refresh(); return(Task.CompletedTask); }); next = now + (uint)(1000 / 60f); } } } }