void NetUpdate()

in doom_py/src/vizdoom/src/d_net.cpp [941:1380]


void NetUpdate (void)
{
	//VIZDOOM_CODE

	int		lowtic;
	int 	nowtime;
	int 	newtics;
	int 	i,j;
	int 	realstart;
	BYTE	*cmddata;
	bool	resendOnly;

	GC::CheckGC();

	//VIZDOOM_CODE
	if(*vizdoom_controlled && !*vizdoom_async) nowtime = gametic;
	else{
		if (ticdup == 0)
		{
			return;
		}

	 	//check time
		nowtime = I_GetTime (false);
	}
	newtics = nowtime - gametime;
	gametime = nowtime;

	if (newtics <= 0)	// nothing new to update
	{
		GetPackets ();
		return;
	}

	if (skiptics <= newtics)
	{
		newtics -= skiptics;
		skiptics = 0;
	}
	else
	{
		skiptics -= newtics;
		newtics = 0;
	}

	// build new ticcmds for console player
	for (i = 0; i < newtics; i++)
	{
		I_StartTic ();
		//VIZDOOM_CODE
		if(!*vizdoom_controlled || (*vizdoom_async && *vizdoom_allow_input)) D_ProcessEvents ();
		if ((maketic - gametic) / ticdup >= BACKUPTICS/2-1) break; // can't hold any more
		//Printf ("mk:%i ",maketic);
		if(!*vizdoom_controlled || *vizdoom_async){
			G_BuildTiccmd (&localcmds[maketic % LOCALCMDTICS]);
			maketic++;
		}

		if (ticdup == 1 || maketic == 0)
		{
			Net_NewMakeTic ();
		}
		else
		{
			// Once ticdup tics have been collected, average their movements
			// and combine their buttons, since they will all be sent as a
			// single tic that gets duplicated ticdup times. Even with ticdup,
			// tics are still collected at the normal rate so that, with the
			// help of prediction, the game seems as responsive as normal.
			if (maketic % ticdup != 0)
			{
				int mod = maketic - maketic % ticdup;
				int j;

				// Update the buttons for all tics in this ticdup set as soon as
				// possible so that the prediction shows jumping as correctly as
				// possible. (If you press +jump in the middle of a ticdup set,
				// the jump will actually begin at the beginning of the set, not
				// in the middle.)
				for (j = maketic-2; j >= mod; --j)
				{
					localcmds[j % LOCALCMDTICS].ucmd.buttons |=
						localcmds[(j + 1) % LOCALCMDTICS].ucmd.buttons;
				}
			}
			else
			{
				// Average the ticcmds between these tics to get the
				// movement that is actually sent across the network. We
				// need to update them in all the localcmds slots that
				// are dupped so that prediction works properly.
				int mod = maketic - ticdup;
				int modp, j;

				int pitch = 0;
				int yaw = 0;
				int roll = 0;
				int forwardmove = 0;
				int sidemove = 0;
				int upmove = 0;

				for (j = 0; j < ticdup; ++j)
				{
					modp = (mod + j) % LOCALCMDTICS;
					pitch += localcmds[modp].ucmd.pitch;
					yaw += localcmds[modp].ucmd.yaw;
					roll += localcmds[modp].ucmd.roll;
					forwardmove += localcmds[modp].ucmd.forwardmove;
					sidemove += localcmds[modp].ucmd.sidemove;
					upmove += localcmds[modp].ucmd.upmove;
				}

				pitch /= ticdup;
				yaw /= ticdup;
				roll /= ticdup;
				forwardmove /= ticdup;
				sidemove /= ticdup;
				upmove /= ticdup;

				for (j = 0; j < ticdup; ++j)
				{
					modp = (mod + j) % LOCALCMDTICS;
					localcmds[modp].ucmd.pitch = pitch;
					localcmds[modp].ucmd.yaw = yaw;
					localcmds[modp].ucmd.roll = roll;
					localcmds[modp].ucmd.forwardmove = forwardmove;
					localcmds[modp].ucmd.sidemove = sidemove;
					localcmds[modp].ucmd.upmove = upmove;
				}

				Net_NewMakeTic ();
			}
		}
	}

	if (singletics)
		return; 		// singletic update is synchronous

	if (demoplayback)
	{
		resendto[0] = nettics[0] = (maketic / ticdup);
		return;			// Don't touch netcmd data while playing a demo, as it'll already exist.
	}

	// If maketic didn't cross a ticdup boundary, only send packets
	// to players waiting for resends.
	resendOnly = (maketic / ticdup) == (maketic - i) / ticdup;

	// send the packet to the other nodes
	int count = 1;
	int quitcount = 0;

	if (consoleplayer == Net_Arbitrator)
	{
		if (NetMode == NET_PacketServer)
		{
			for (j = 0; j < MAXPLAYERS; j++)
			{
				if (playeringame[j] && players[j].Bot == NULL)
				{
					count++;
				}
			}

			// The loop above added the local player to the count a second time,
			// and it also added the player being sent the packet to the count.
			count -= 2;

			for (j = 0; j < doomcom.numnodes; ++j)
			{
				if (nodejustleft[j])
				{
					if (count == 0)
					{
						PlayerIsGone (j, playerfornode[j]);
					}
					else
					{
						quitcount++;
					}
				}
			}

			if (count == 0)
			{
				count = 1;
			}
		}
	}

	for (i = 0; i < doomcom.numnodes; i++)
	{
		BYTE playerbytes[MAXPLAYERS];

		if (!nodeingame[i])
		{
			continue;
		}
		if (NetMode == NET_PacketServer &&
			consoleplayer != Net_Arbitrator &&
			i != nodeforplayer[Net_Arbitrator] &&
			i != 0)
		{
			continue;
		}
		if (resendOnly && resendcount[i] <= 0 && !remoteresend[i] && nettics[i])
		{
			continue;
		}

		int numtics;
		int k;

		lowtic = maketic / ticdup;

		netbuffer[0] = 0;
		netbuffer[1] = realstart = resendto[i];
		k = 2;

		if (NetMode == NET_PacketServer &&
			consoleplayer == Net_Arbitrator &&
			i != 0)
		{
			for (j = 1; j < doomcom.numnodes; ++j)
			{
				if (nodeingame[j] && nettics[j] < lowtic && j != i)
				{
					lowtic = nettics[j];
				}
			}
			netbuffer[k++] = lowtic;
		}

		numtics = MAX(0, lowtic - realstart);
		if (numtics > BACKUPTICS)
			I_Error ("NetUpdate: Node %d missed too many tics", i);

		switch (net_extratic)
		{
		case 0:
		default: 
			resendto[i] = lowtic; break;
		case 1: resendto[i] = MAX(0, lowtic - 1); break;
		case 2: resendto[i] = nettics[i]; break;
		}

		if (numtics == 0 && resendOnly && !remoteresend[i] && nettics[i])
		{
			continue;
		}

		if (remoteresend[i])
		{
			netbuffer[0] |= NCMD_RETRANSMIT;
			netbuffer[k++] = nettics[i];
		}

		if (numtics < 3)
		{
			netbuffer[0] |= numtics;
		}
		else
		{
			netbuffer[0] |= NCMD_XTICS;
			netbuffer[k++] = numtics - 3;
		}

		if (quitcount > 0)
		{
			netbuffer[0] |= NCMD_QUITTERS;
			netbuffer[k++] = quitcount;
			for (int l = 0; l < doomcom.numnodes; ++l)
			{
				if (nodejustleft[l])
				{
					netbuffer[k++] = playerfornode[l];
				}
			}
		}

		// Send current network delay
		// The number of tics we just made should be removed from the count.
		netbuffer[k++] = ((maketic - numtics - gametic) / ticdup);

		if (numtics > 0)
		{
			int l;

			if (count > 1 && i != 0 && consoleplayer == Net_Arbitrator)
			{
				netbuffer[0] |= NCMD_MULTI;
				netbuffer[k++] = count;

				if (NetMode == NET_PacketServer)
				{
					for (l = 1, j = 0; j < MAXPLAYERS; j++)
					{
						if (playeringame[j] && players[j].Bot == NULL && j != playerfornode[i] && j != consoleplayer)
						{
							playerbytes[l++] = j;
							netbuffer[k++] = j;
						}
					}
				}
			}

			cmddata = &netbuffer[k];

			for (l = 0; l < count; ++l)
			{
				for (j = 0; j < numtics; j++)
				{
					int start = realstart + j, prev = start - 1;
					int localstart, localprev;

					localstart = (start * ticdup) % LOCALCMDTICS;
					localprev = (prev * ticdup) % LOCALCMDTICS;
					start %= BACKUPTICS;
					prev %= BACKUPTICS;

					// The local player has their tics sent first, followed by
					// the other players.
					if (l == 0)
					{
						WriteWord (localcmds[localstart].consistancy, &cmddata);
						// [RH] Write out special "ticcmds" before real ticcmd
						if (specials.used[start])
						{
							memcpy (cmddata, specials.streams[start], specials.used[start]);
							cmddata += specials.used[start];
						}
						WriteUserCmdMessage (&localcmds[localstart].ucmd,
							localprev >= 0 ? &localcmds[localprev].ucmd : NULL, &cmddata);
					}
					else if (i != 0)
					{
						int len;
						BYTE *spec;

						WriteWord (netcmds[playerbytes[l]][start].consistancy, &cmddata);
						spec = NetSpecs[playerbytes[l]][start].GetData (&len);
						if (spec != NULL)
						{
							memcpy (cmddata, spec, len);
							cmddata += len;
						}

						WriteUserCmdMessage (&netcmds[playerbytes[l]][start].ucmd,
							prev >= 0 ? &netcmds[playerbytes[l]][prev].ucmd : NULL, &cmddata);
					}
				}
			}
			HSendPacket (i, int(cmddata - netbuffer));
		}
		else
		{
			HSendPacket (i, k);
		}
	}

	// listen for other packets
	GetPackets ();

	if (!resendOnly)
	{
		// ideally nettics[0] should be 1 - 3 tics above lowtic
		// if we are consistantly slower, speed up time

		// [RH] I had erroneously assumed frameskip[] had 4 entries
		// because there were 4 players, but that's not the case at
		// all. The game is comparing the lag behind the master for
		// four runs of TryRunTics. If our tic count is ahead of the
		// master all 4 times, the next run of NetUpdate will not
		// process any new input. If we have less input than the
		// master, the next run of NetUpdate will process extra tics
		// (because gametime gets decremented here).

		// the key player does not adapt
		if (consoleplayer != Net_Arbitrator)
		{
			// I'm not sure about this when using a packet server, because
			// if left unmodified from the P2P version, it can make the game
			// very jerky. The way I have it written right now basically means
			// that it won't adapt. Fortunately, player prediction helps
			// alleviate the lag somewhat.

			if (NetMode == NET_PeerToPeer)
			{
				int totalavg = 0;
				if (net_ticbalance)
				{
					// Try to guess ahead the time it takes to send responses to the slowest node
					int nodeavg = 0, arbavg = 0;

					for (j = 0; j < BACKUPTICS; j++)
					{
						arbavg += netdelay[nodeforplayer[Net_Arbitrator]][j];
						nodeavg += netdelay[0][j];
					}
					arbavg /= BACKUPTICS;
					nodeavg /= BACKUPTICS;

					// We shouldn't adapt if we are already the arbitrator isn't what we are waiting for, otherwise it just adds more latency
					if (arbavg > nodeavg)
					{
						lastaverage = totalavg = ((arbavg + nodeavg) / 2);
					}
					else
					{
						// Allow room to guess two tics ahead
						if (nodeavg > (arbavg + 2) && lastaverage > 0)
							lastaverage--;
						totalavg = lastaverage;
					}
				}
					
				mastertics = nettics[nodeforplayer[Net_Arbitrator]] + totalavg;
			}
			if (nettics[0] <= mastertics)
			{
				gametime--;
				if (debugfile) fprintf(debugfile, "-");
			}
			if (NetMode != NET_PacketServer)
			{
				frameskip[(maketic / ticdup) & 3] = (oldnettics > mastertics);
			}
			else
			{
				frameskip[(maketic / ticdup) & 3] = (oldnettics - mastertics) > 3;
			}
			if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
			{
				skiptics = 1;
				if (debugfile) fprintf(debugfile, "+");
			}
			oldnettics = nettics[0];
		}
	}
}