Merge branch 'master' into gonesolong

Conflicts:
	src/CMakeLists.txt
	src/b_think.cpp
	src/g_doom/a_doomweaps.cpp
	src/g_hexen/a_clericstaff.cpp
	src/g_hexen/a_fighterplayer.cpp
	src/namedef.h
	src/p_enemy.cpp
	src/p_local.h
	src/p_mobj.cpp
	src/p_teleport.cpp
	src/sc_man_tokens.h
	src/thingdef/thingdef_codeptr.cpp
	src/thingdef/thingdef_function.cpp
	src/thingdef/thingdef_parse.cpp
	wadsrc/static/actors/actor.txt
	wadsrc/static/actors/constants.txt
	wadsrc/static/actors/shared/inventory.txt

- Added register reuse to VMFunctionBuilder for FxPick's code emitter.
- Note to self: Need to reimplement IsPointerEqual and CheckClass, which
  were added to thingdef_function.cpp over the past year, as this file no
  longer exists in this branch.
This commit is contained in:
Randy Heit 2014-12-21 20:43:24 -06:00
commit b5e4153c78
182 changed files with 23025 additions and 8730 deletions

View file

@ -39,7 +39,6 @@
#include "cmdlib.h"
#include "s_sound.h"
#include "m_cheat.h"
#include "p_effect.h"
#include "p_local.h"
#include "c_dispatch.h"
#include "sbar.h"
@ -110,13 +109,15 @@ unsigned int lastrecvtime[MAXPLAYERS]; // [RH] Used for pings
unsigned int currrecvtime[MAXPLAYERS];
unsigned int lastglobalrecvtime; // Identify the last time a packet was recieved.
bool hadlate;
int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times.
int lastaverage;
int nodeforplayer[MAXPLAYERS];
int playerfornode[MAXNETNODES];
int maketic;
int skiptics;
int ticdup;
int ticdup;
void D_ProcessEvents (void);
void G_BuildTiccmd (ticcmd_t *cmd);
@ -151,6 +152,32 @@ CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
}
}
CVAR(Bool, net_ticbalance, false, CVAR_SERVERINFO | CVAR_NOSAVE)
CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO | CVAR_NOSAVE)
{
if (self < 0)
{
self = 0;
}
else if (self > 2)
{
self = 2;
}
}
#ifdef _DEBUG
CVAR(Int, net_fakelatency, 0, 0);
struct PacketStore
{
int timer;
doomcom_t message;
};
static TArray<PacketStore> InBuffer;
static TArray<PacketStore> OutBuffer;
#endif
// [RH] Special "ticcmds" get stored in here
static struct TicSpecial
{
@ -347,6 +374,9 @@ int NetbufferSize ()
k += netbuffer[k] + 1;
}
// Network delay byte
k++;
if (netbuffer[0] & NCMD_MULTI)
{
count = netbuffer[k];
@ -487,7 +517,30 @@ void HSendPacket (int node, int len)
doomcom.remotenode = node;
doomcom.datalength = len;
I_NetCmd ();
#ifdef _DEBUG
if (net_fakelatency / 2 > 0)
{
PacketStore store;
store.message = doomcom;
store.timer = I_GetTime(false) + ((net_fakelatency / 2) / (1000 / TICRATE));
OutBuffer.Push(store);
}
else
I_NetCmd();
for (unsigned int i = 0; i < OutBuffer.Size(); i++)
{
if (OutBuffer[i].timer <= I_GetTime(false))
{
doomcom = OutBuffer[i].message;
I_NetCmd();
OutBuffer.Delete(i);
i = -1;
}
}
#else
I_NetCmd();
#endif
}
//
@ -509,12 +562,42 @@ bool HGetPacket (void)
if (demoplayback)
return false;
doomcom.command = CMD_GET;
I_NetCmd ();
#ifdef _DEBUG
if (net_fakelatency / 2 > 0 && doomcom.remotenode != -1)
{
PacketStore store;
store.message = doomcom;
store.timer = I_GetTime(false) + ((net_fakelatency / 2) / (1000 / TICRATE));
InBuffer.Push(store);
doomcom.remotenode = -1;
}
if (doomcom.remotenode == -1)
{
bool gotmessage = false;
for (unsigned int i = 0; i < InBuffer.Size(); i++)
{
if (InBuffer[i].timer <= I_GetTime(false))
{
doomcom = InBuffer[i].message;
InBuffer.Delete(i);
gotmessage = true;
break;
}
}
if (!gotmessage)
return false;
}
#else
if (doomcom.remotenode == -1)
{
return false;
}
#endif
if (debugfile)
{
@ -570,6 +653,9 @@ bool HGetPacket (void)
if (doomcom.datalength != NetbufferSize ())
{
Printf("Bad packet length %i (calculated %i)\n",
doomcom.datalength, NetbufferSize());
if (debugfile)
fprintf (debugfile,"---bad packet length %i (calculated %i)\n",
doomcom.datalength, NetbufferSize());
@ -583,6 +669,9 @@ void PlayerIsGone (int netnode, int netconsole)
{
int i;
if (!nodeingame[netnode])
return;
for (i = netnode + 1; i < doomcom.numnodes; ++i)
{
if (nodeingame[i])
@ -593,77 +682,37 @@ void PlayerIsGone (int netnode, int netconsole)
doomcom.numnodes = netnode;
}
if (playeringame[netconsole])
{
players[netconsole].playerstate = PST_GONE;
}
nodeingame[netnode] = false;
playeringame[netconsole] = false;
nodejustleft[netnode] = false;
if (deathmatch)
{
Printf ("%s left the game with %d frags\n",
players[netconsole].userinfo.GetName(),
players[netconsole].fragcount);
}
else
{
Printf ("%s left the game\n", players[netconsole].userinfo.GetName());
}
// [RH] Revert each player to their own view if spying through the player who left
for (int ii = 0; ii < MAXPLAYERS; ++ii)
{
if (playeringame[ii] && players[ii].camera == players[netconsole].mo)
{
players[ii].camera = players[ii].mo;
if (ii == consoleplayer && StatusBar != NULL)
{
StatusBar->AttachToPlayer (&players[ii]);
}
}
}
// [RH] Make the player disappear
FBehavior::StaticStopMyScripts (players[netconsole].mo);
if (players[netconsole].mo != NULL)
{
P_DisconnectEffect (players[netconsole].mo);
players[netconsole].mo->player = NULL;
players[netconsole].mo->Destroy ();
if (!(players[netconsole].mo->ObjectFlags & OF_EuthanizeMe))
{ // We just destroyed a morphed player, so now the original player
// has taken their place. Destroy that one too.
players[netconsole].mo->Destroy();
}
players[netconsole].mo = NULL;
players[netconsole].camera = NULL;
}
// [RH] Let the scripts know the player left
FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, NULL, true, netconsole);
if (netconsole == Net_Arbitrator)
{
bglobal.RemoveAllBots (true);
Printf ("Removed all bots\n");
// Pick a new network arbitrator
for (int i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].isbot)
if (i != netconsole && playeringame[i] && players[i].Bot == NULL)
{
Net_Arbitrator = i;
players[i].settings_controller = true;
Printf ("%s is the new arbitrator\n", players[i].userinfo.GetName());
Printf("%s is the new arbitrator\n", players[i].userinfo.GetName());
break;
}
}
if (debugfile && NetMode == NET_PacketServer)
}
if (debugfile && NetMode == NET_PacketServer)
{
if (Net_Arbitrator == consoleplayer)
{
if (Net_Arbitrator == consoleplayer)
{
fprintf (debugfile, "I am the new master!\n");
}
else
{
fprintf (debugfile, "Node %d is the new master!\n", nodeforplayer[Net_Arbitrator]);
}
fprintf(debugfile, "I am the new master!\n");
}
else
{
fprintf(debugfile, "Node %d is the new master!\n", nodeforplayer[Net_Arbitrator]);
}
}
@ -772,7 +821,6 @@ void GetPackets (void)
}
if (netbuffer[0] & NCMD_QUITTERS)
{
numplayers = netbuffer[k++];
for (int i = 0; i < numplayers; ++i)
@ -782,6 +830,9 @@ void GetPackets (void)
}
}
// Pull current network delay from node
netdelay[netnode][(nettics[netnode]+1) % BACKUPTICS] = netbuffer[k++];
playerbytes[0] = netconsole;
if (netbuffer[0] & NCMD_MULTI)
{
@ -847,64 +898,18 @@ void GetPackets (void)
for (i = 0; i < numplayers; ++i)
{
int node = !players[playerbytes[i]].isbot ?
nodeforplayer[playerbytes[i]] : netnode;
int node = nodeforplayer[playerbytes[i]];
SkipTicCmd (&start, nettics[node] - realstart);
for (tics = nettics[node]; tics < realend; tics++)
ReadTicCmd (&start, playerbytes[i], tics);
}
// Update the number of tics received from each node. This must
// be separate from the above loop in case the master is also
// sending bot movements. If it's not separate, then the bots
// will only move on the master, because the other players will
// read the master's tics and then think they already got all
// the tics for the bots and skip the bot tics included in the
// packet.
for (i = 0; i < numplayers; ++i)
{
if (!players[playerbytes[i]].isbot)
{
nettics[nodeforplayer[playerbytes[i]]] = realend;
}
}
}
}
}
void AdjustBots (int gameticdiv)
{
// [RH] This loop adjusts the bots' rotations for ticcmds that have
// been already created but not yet executed. This way, the bot is still
// able to create ticcmds that accurately reflect the state it wants to
// be in even when gametic lags behind maketic.
for (int i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].isbot && players[i].mo)
{
players[i].savedyaw = players[i].mo->angle;
players[i].savedpitch = players[i].mo->pitch;
for (int j = gameticdiv; j < maketic/ticdup; j++)
{
players[i].mo->angle += (netcmds[i][j%BACKUPTICS].ucmd.yaw << 16) * ticdup;
players[i].mo->pitch -= (netcmds[i][j%BACKUPTICS].ucmd.pitch << 16) * ticdup;
nettics[nodeforplayer[playerbytes[i]]] = realend;
}
}
}
}
void UnadjustBots ()
{
for (int i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].isbot && players[i].mo)
{
players[i].mo->angle = players[i].savedyaw;
players[i].mo->pitch = players[i].savedpitch;
}
}
}
//
// NetUpdate
// Builds ticcmds for console player,
@ -934,7 +939,7 @@ void NetUpdate (void)
newtics = nowtime - gametime;
gametime = nowtime;
if (newtics <= 0) // nothing new to update
if (newtics <= 0 || pauseext) // nothing new to update or window paused
{
GetPackets ();
return;
@ -951,9 +956,7 @@ void NetUpdate (void)
newtics = 0;
}
// build new ticcmds for console player (and bots if I am the arbitrator)
AdjustBots (gametic / ticdup);
// build new ticcmds for console player
for (i = 0; i < newtics; i++)
{
I_StartTic ();
@ -963,11 +966,6 @@ void NetUpdate (void)
//Printf ("mk:%i ",maketic);
G_BuildTiccmd (&localcmds[maketic % LOCALCMDTICS]);
if (maketic % ticdup == 0)
{
//Added by MC: For some of that bot stuff. The main bot function.
bglobal.Main ((maketic / ticdup) % BACKUPTICS);
}
maketic++;
if (ticdup == 1 || maketic == 0)
@ -1047,8 +1045,6 @@ void NetUpdate (void)
}
}
UnadjustBots ();
if (singletics)
return; // singletic update is synchronous
@ -1068,14 +1064,11 @@ void NetUpdate (void)
if (consoleplayer == Net_Arbitrator)
{
for (j = 0; j < MAXPLAYERS; j++)
for (j = 0; j < doomcom.numnodes; j++)
{
if (playeringame[j])
if (nodeingame[j] && NetMode == NET_PacketServer)
{
if (players[j].isbot || NetMode == NET_PacketServer)
{
count++;
}
count++;
}
}
@ -1150,11 +1143,18 @@ void NetUpdate (void)
netbuffer[k++] = lowtic;
}
numtics = lowtic - realstart;
numtics = MAX(0, lowtic - realstart);
if (numtics > BACKUPTICS)
I_Error ("NetUpdate: Node %d missed too many tics", i);
resendto[i] = MAX (0, lowtic - doomcom.extratics);
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])
{
@ -1190,6 +1190,10 @@ void NetUpdate (void)
}
}
// Send current network delay
// The number of tics we just made should be removed from the count.
netbuffer[k++] = ((maketic - newtics - gametic) / ticdup);
if (numtics > 0)
{
int l;
@ -1199,15 +1203,12 @@ void NetUpdate (void)
netbuffer[0] |= NCMD_MULTI;
netbuffer[k++] = count;
for (l = 1, j = 0; j < MAXPLAYERS; j++)
for (l = 1, j = 0; j < doomcom.numnodes; j++)
{
if (playeringame[j] && j != playerfornode[i] && j != consoleplayer)
if (nodeingame[j] && j != i && j != nodeforplayer[consoleplayer] && NetMode == NET_PacketServer)
{
if (players[j].isbot || NetMode == NET_PacketServer)
{
playerbytes[l++] = j;
netbuffer[k++] = j;
}
playerbytes[l++] = playerfornode[j];
netbuffer[k++] = playerfornode[j];
}
}
}
@ -1227,7 +1228,7 @@ void NetUpdate (void)
prev %= BACKUPTICS;
// The local player has their tics sent first, followed by
// the other players/bots.
// the other players.
if (l == 0)
{
WriteWord (localcmds[localstart].consistancy, &cmddata);
@ -1242,24 +1243,17 @@ void NetUpdate (void)
}
else if (i != 0)
{
if (players[playerbytes[l]].isbot)
{
int len;
BYTE *spec;
WriteWord (0, &cmddata); // fake consistancy word
}
else
WriteWord (netcmds[playerbytes[l]][start].consistancy, &cmddata);
spec = NetSpecs[playerbytes[l]][start].GetData (&len);
if (spec != NULL)
{
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;
}
memcpy (cmddata, spec, len);
cmddata += len;
}
WriteUserCmdMessage (&netcmds[playerbytes[l]][start].ucmd,
prev >= 0 ? &netcmds[playerbytes[l]][prev].ucmd : NULL, &cmddata);
}
@ -1299,9 +1293,37 @@ void NetUpdate (void)
// that it won't adapt. Fortunately, player prediction helps
// alleviate the lag somewhat.
if (NetMode != NET_PacketServer)
if (NetMode == NET_PeerToPeer)
{
mastertics = nettics[nodeforplayer[Net_Arbitrator]];
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)
{
@ -1346,9 +1368,8 @@ void NetUpdate (void)
//
// 0 One byte set to NCMD_SETUP+2
// 1 One byte for ticdup setting
// 2 One byte for extratics setting
// 3 One byte for NetMode setting
// 4 String with starting map's name
// 2 One byte for NetMode setting
// 3 String with starting map's name
// . Four bytes for the RNG seed
// . Stream containing remaining game info
//
@ -1429,10 +1450,9 @@ bool DoArbitrate (void *userdata)
data->gotsetup[0] = 0x80;
ticdup = doomcom.ticdup = netbuffer[1];
doomcom.extratics = netbuffer[2];
NetMode = netbuffer[3];
NetMode = netbuffer[2];
stream = &netbuffer[4];
stream = &netbuffer[3];
s = ReadString (&stream);
startmap = s;
delete[] s;
@ -1497,9 +1517,8 @@ bool DoArbitrate (void *userdata)
{
netbuffer[0] = NCMD_SETUP+2;
netbuffer[1] = (BYTE)doomcom.ticdup;
netbuffer[2] = (BYTE)doomcom.extratics;
netbuffer[3] = NetMode;
stream = &netbuffer[4];
netbuffer[2] = NetMode;
stream = &netbuffer[3];
WriteString (startmap, &stream);
WriteLong (rngseed, &stream);
C_WriteCVars (&stream, CVAR_SERVERINFO, true);
@ -1634,10 +1653,19 @@ void D_CheckNetGame (void)
resendto[i] = 0; // which tic to start sending
}
// Packet server has proven to be rather slow over the internet. Print a warning about it.
v = Args->CheckValue("-netmode");
if (v != NULL && (atoi(v) != 0))
{
Printf(TEXTCOLOR_YELLOW "Notice: Using PacketServer (netmode 1) over the internet is prone to running too slow on some internet configurations."
"\nIf the game is running well below expected speeds, use netmode 0 (P2P) instead.\n");
}
// I_InitNetwork sets doomcom and netgame
if (I_InitNetwork ())
{
NetMode = NET_PacketServer;
// For now, stop auto selecting PacketServer, as it's more likely to cause confusion.
//NetMode = NET_PacketServer;
}
if (doomcom.id != DOOMCOM_ID)
{
@ -1647,15 +1675,23 @@ void D_CheckNetGame (void)
consoleplayer = doomcom.consoleplayer;
v = Args->CheckValue ("-netmode");
if (v != NULL)
if (consoleplayer == Net_Arbitrator)
{
NetMode = atoi (v) != 0 ? NET_PacketServer : NET_PeerToPeer;
}
if (doomcom.numnodes > 1)
{
Printf ("Selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode. (%s)\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server",
v != NULL ? "forced" : "auto");
v = Args->CheckValue("-netmode");
if (v != NULL)
{
NetMode = atoi(v) != 0 ? NET_PacketServer : NET_PeerToPeer;
}
if (doomcom.numnodes > 1)
{
Printf("Selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode. (%s)\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server",
v != NULL ? "forced" : "auto");
}
if (Args->CheckParm("-extratic"))
{
net_extratic = 1;
}
}
// [RH] Setup user info
@ -1683,6 +1719,11 @@ void D_CheckNetGame (void)
for (i = 0; i < doomcom.numnodes; i++)
nodeingame[i] = true;
if (consoleplayer != Net_Arbitrator && doomcom.numnodes > 1)
{
Printf("Arbitrator selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode.\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server");
}
Printf ("player %i of %i (%i nodes)\n",
consoleplayer+1, doomcom.numplayers, doomcom.numnodes);
}
@ -1809,6 +1850,9 @@ void TryRunTics (void)
{
C_Ticker();
M_Ticker();
// Repredict the player for new buffered movement
P_UnPredictPlayer();
P_PredictPlayer(&players[consoleplayer]);
}
return;
}
@ -1844,6 +1888,9 @@ void TryRunTics (void)
{
C_Ticker ();
M_Ticker ();
// Repredict the player for new buffered movement
P_UnPredictPlayer();
P_PredictPlayer(&players[consoleplayer]);
return;
}
}
@ -1857,6 +1904,7 @@ void TryRunTics (void)
// run the count tics
if (counts > 0)
{
P_UnPredictPlayer();
while (counts--)
{
if (gametic > lowtic)
@ -1876,6 +1924,7 @@ void TryRunTics (void)
NetUpdate (); // check for new console commands
}
P_PredictPlayer(&players[consoleplayer]);
S_UpdateSounds (players[consoleplayer].camera); // move positional sounds
}
}
@ -2130,10 +2179,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
break;
case DEM_ADDBOT:
{
BYTE num = ReadByte (stream);
bglobal.DoAddBot (num, s = ReadString (stream));
}
bglobal.TryAddBot (stream, player);
break;
case DEM_KILLBOTS:
@ -2589,10 +2635,13 @@ void Net_SkipCommand (int type, BYTE **stream)
switch (type)
{
case DEM_SAY:
case DEM_ADDBOT:
skip = strlen ((char *)(*stream + 1)) + 2;
break;
case DEM_ADDBOT:
skip = strlen ((char *)(*stream + 1)) + 6;
break;
case DEM_GIVECHEAT:
case DEM_TAKECHEAT:
skip = strlen ((char *)(*stream)) + 3;
@ -2713,7 +2762,6 @@ void Net_SkipCommand (int type, BYTE **stream)
CCMD (pings)
{
int i;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i],
@ -2755,7 +2803,7 @@ static void Network_Controller (int playernum, bool add)
return;
}
if (players[playernum].isbot)
if (players[playernum].Bot != NULL)
{
Printf ("Bots cannot be added to the controller list.\n");
return;