This commit is contained in:
Christoph Oelckers 2014-09-26 08:31:20 +02:00
commit 0f62983aee
16 changed files with 410 additions and 61 deletions

View File

@ -756,9 +756,9 @@ void D_Display ()
}
screen->SetBlendingRect(viewwindowx, viewwindowy,
viewwindowx + viewwidth, viewwindowy + viewheight);
P_PredictPlayer(&players[consoleplayer]);
Renderer->RenderView(&players[consoleplayer]);
P_UnPredictPlayer();
if ((hw2d = screen->Begin2D(viewactive)))
{
// Redraw everything every frame when using 2D accel

View File

@ -110,6 +110,8 @@ 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];
@ -151,6 +153,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 +375,9 @@ int NetbufferSize ()
k += netbuffer[k] + 1;
}
// Network delay byte
k++;
if (netbuffer[0] & NCMD_MULTI)
{
count = netbuffer[k];
@ -487,7 +518,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
}
//
@ -513,8 +567,38 @@ bool HGetPacket (void)
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 +654,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());
@ -782,6 +869,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)
{
@ -1150,11 +1240,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 +1287,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;
@ -1299,9 +1400,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 +1475,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 +1557,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 +1624,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);
@ -1647,17 +1773,25 @@ void D_CheckNetGame (void)
consoleplayer = doomcom.consoleplayer;
v = Args->CheckValue ("-netmode");
if (consoleplayer == Net_Arbitrator)
{
v = Args->CheckValue("-netmode");
if (v != NULL)
{
NetMode = atoi (v) != 0 ? NET_PacketServer : NET_PeerToPeer;
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",
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
D_SetupUserInfo ();
@ -1683,6 +1817,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 +1948,9 @@ void TryRunTics (void)
{
C_Ticker();
M_Ticker();
// Repredict the player for new buffered movement
P_UnPredictPlayer();
P_PredictPlayer(&players[consoleplayer]);
}
return;
}
@ -1844,6 +1986,9 @@ void TryRunTics (void)
{
C_Ticker ();
M_Ticker ();
// Repredict the player for new buffered movement
P_UnPredictPlayer();
P_PredictPlayer(&players[consoleplayer]);
return;
}
}
@ -1857,6 +2002,7 @@ void TryRunTics (void)
// run the count tics
if (counts > 0)
{
P_UnPredictPlayer();
while (counts--)
{
if (gametic > lowtic)
@ -1876,6 +2022,7 @@ void TryRunTics (void)
NetUpdate (); // check for new console commands
}
P_PredictPlayer(&players[consoleplayer]);
S_UpdateSounds (players[consoleplayer].camera); // move positional sounds
}
}
@ -2713,7 +2860,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],

View File

@ -70,7 +70,6 @@ struct doomcom_t
// info common to all nodes
SWORD numnodes; // console is always node 0.
SWORD ticdup; // 1 = no duplication, 2-5 = dup for slow nets
SWORD extratics; // 1 = send a backup tic in every packet
#ifdef DJGPP
SWORD pad[5]; // keep things aligned for DOS drivers
#endif
@ -143,6 +142,8 @@ extern struct ticcmd_t localcmds[LOCALCMDTICS];
extern int maketic;
extern int nettics[MAXNETNODES];
extern int netdelay[MAXNETNODES][BACKUPTICS];
extern int nodeforplayer[MAXPLAYERS];
extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
extern int ticdup;

View File

@ -37,6 +37,7 @@
// copy would be.
#include "doomtype.h"
#include "doomdef.h"
#include "v_video.h"
#include "gi.h"
#include "c_cvars.h"
@ -48,6 +49,7 @@
#include "p_local.h"
#include "doomstat.h"
#include "g_level.h"
#include "d_net.h"
#include <time.h>
@ -73,6 +75,7 @@ CVAR (Bool, hud_showscore, false, CVAR_ARCHIVE); // for user maintained score
CVAR (Bool, hud_showweapons, true, CVAR_ARCHIVE); // Show weapons collected
CVAR (Int , hud_showtime, 0, CVAR_ARCHIVE); // Show time on HUD
CVAR (Int , hud_timecolor, CR_GOLD,CVAR_ARCHIVE); // Color of in-game time on HUD
CVAR (Int , hud_showlag, 0, CVAR_ARCHIVE); // Show input latency (maketic - gametic difference)
CVAR (Int, hud_ammo_red, 25, CVAR_ARCHIVE) // ammo percent less than which status is red
CVAR (Int, hud_ammo_yellow, 50, CVAR_ARCHIVE) // ammo percent less is yellow more green
@ -917,6 +920,51 @@ static void DrawTime()
DrawHudText(SmallFont, hud_timecolor, timeString, hudwidth - width, height, FRACUNIT);
}
//---------------------------------------------------------------------------
//
// Draw in-game latency
//
//---------------------------------------------------------------------------
static void DrawLatency()
{
if (hud_showlag <= 0 ||
(hud_showlag == 1 && !netgame) ||
hud_showlag > 2)
{
return;
}
int i, localdelay = 0, arbitratordelay = 0;
for (i = 0; i < BACKUPTICS; i++) localdelay += netdelay[0][i];
for (i = 0; i < BACKUPTICS; i++) arbitratordelay += netdelay[nodeforplayer[Net_Arbitrator]][i];
localdelay = ((localdelay / BACKUPTICS) * ticdup) * (1000 / TICRATE);
arbitratordelay = ((arbitratordelay / BACKUPTICS) * ticdup) * (1000 / TICRATE);
int color = CR_GREEN;
if (MAX(localdelay, arbitratordelay) > 200)
{
color = CR_YELLOW;
}
if (MAX(localdelay, arbitratordelay) > 400)
{
color = CR_ORANGE;
}
if (MAX(localdelay, arbitratordelay) >= ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE))
{
color = CR_RED;
}
char tempstr[32];
const int millis = (level.time % TICRATE) * (1000 / TICRATE);
mysnprintf(tempstr, sizeof(tempstr), "a:%dms - l:%dms", arbitratordelay, localdelay);
const int characterCount = strlen(tempstr);
const int width = SmallFont->GetCharWidth('0') * characterCount + 2; // small offset from screen's border
const int height = SmallFont->GetHeight() * 2;
DrawHudText(SmallFont, color, tempstr, hudwidth - width, height, FRACUNIT);
}
//---------------------------------------------------------------------------
//
@ -982,6 +1030,7 @@ void DrawHUD()
if (idmypos) DrawCoordinates(CPlayer);
DrawTime();
DrawLatency();
}
else
{

View File

@ -48,6 +48,7 @@
#include "d_player.h"
#include "hu_stuff.h"
#include "gstrings.h"
#include "d_net.h"
// MACROS ------------------------------------------------------------------
@ -61,7 +62,7 @@
static void HU_DoDrawScores (player_t *, player_t *[MAXPLAYERS]);
static void HU_DrawTimeRemaining (int y);
static void HU_DrawPlayer (player_t *, bool, int, int, int, int, int, int, int, int);
static void HU_DrawPlayer(player_t *, bool, int, int, int, int, int, int, int, int, int);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
@ -228,7 +229,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
int maxnamewidth, maxscorewidth, maxiconheight;
int numTeams = 0;
int x, y, ypadding, bottom;
int col2, col3, col4;
int col2, col3, col4, col5;
if (deathmatch)
{
@ -309,12 +310,14 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
const char *text_color = GStrings("SCORE_COLOR"),
*text_frags = GStrings(deathmatch ? "SCORE_FRAGS" : "SCORE_KILLS"),
*text_name = GStrings("SCORE_NAME");
*text_name = GStrings("SCORE_NAME"),
*text_delay = GStrings("SCORE_DELAY");
col2 = (SmallFont->StringWidth(text_color) + 8) * CleanXfac;
col3 = col2 + (SmallFont->StringWidth(text_frags) + 8) * CleanXfac;
col4 = col3 + maxscorewidth * CleanXfac;
x = (SCREENWIDTH >> 1) - ((maxnamewidth * CleanXfac + col4) >> 1);
col5 = col4 + (maxnamewidth + 8) * CleanXfac;
x = (SCREENWIDTH >> 1) - (((SmallFont->StringWidth(text_delay) * CleanXfac) + col5) >> 1);
screen->DrawText (SmallFont, color, x, y, text_color,
DTA_CleanNoMove, true, TAG_DONE);
@ -325,6 +328,9 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
screen->DrawText (SmallFont, color, x + col4, y, text_name,
DTA_CleanNoMove, true, TAG_DONE);
screen->DrawText(SmallFont, color, x + col5, y, text_delay,
DTA_CleanNoMove, true, TAG_DONE);
y += height + 6 * CleanYfac;
bottom -= height;
@ -332,7 +338,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
{
if (playeringame[sortedplayers[i] - players])
{
HU_DrawPlayer (sortedplayers[i], player==sortedplayers[i], x, col2, col3, col4, maxnamewidth, y, ypadding, lineheight);
HU_DrawPlayer(sortedplayers[i], player == sortedplayers[i], x, col2, col3, col4, col5, maxnamewidth, y, ypadding, lineheight);
y += lineheight + CleanYfac;
}
}
@ -377,7 +383,7 @@ static void HU_DrawTimeRemaining (int y)
//
//==========================================================================
static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int col3, int col4, int maxnamewidth, int y, int ypadding, int height)
static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int col3, int col4, int col5, int maxnamewidth, int y, int ypadding, int height)
{
int color;
char str[80];
@ -387,12 +393,13 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
// The teamplay mode uses colors to show teams, so we need some
// other way to do highlighting. And it may as well be used for
// all modes for the sake of consistancy.
screen->Dim(MAKERGB(200,245,255), 0.125f, col1 - 12*CleanXfac, y - 1, col4 + (maxnamewidth + 24)*CleanXfac, height + 2);
screen->Dim(MAKERGB(200,245,255), 0.125f, col1 - 12*CleanXfac, y - 1, col5 + (maxnamewidth + 24)*CleanXfac, height + 2);
}
col2 += col1;
col3 += col1;
col4 += col1;
col5 += col1;
color = HU_GetRowColor(player, highlight);
HU_DrawColorBar(col1, y, height, (int)(player - players));
@ -412,6 +419,18 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.GetName(),
DTA_CleanNoMove, true, TAG_DONE);
int avgdelay = 0;
for (int i = 0; i < BACKUPTICS; i++)
{
avgdelay += netdelay[nodeforplayer[(int)(player - players)]][i];
}
avgdelay /= BACKUPTICS;
mysnprintf(str, countof(str), "%d", (avgdelay * ticdup) * (1000 / TICRATE));
screen->DrawText(SmallFont, color, col5, y + ypadding, str,
DTA_CleanNoMove, true, TAG_DONE);
if (teamplay && Teams[player->userinfo.GetTeam()].GetLogo().IsNotEmpty ())
{
FTexture *pic = TexMan[Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()];

View File

@ -208,11 +208,11 @@ void PacketSend (void)
{
I_FatalError("Netbuffer overflow!");
}
assert(!(doomcom.data[0] & NCMD_COMPRESSED));
uLong size = TRANSMIT_SIZE - 1;
if (doomcom.datalength >= 10)
{
assert(!(doomcom.data[0] & NCMD_COMPRESSED));
TransmitBuffer[0] = doomcom.data[0] | NCMD_COMPRESSED;
c = compress2(TransmitBuffer + 1, &size, doomcom.data + 1, doomcom.datalength - 1, 9);
size += 1;
@ -938,11 +938,6 @@ bool I_InitNetwork (void)
doomcom.ticdup = 1;
}
if (Args->CheckParm ("-extratic"))
doomcom.extratics = 1;
else
doomcom.extratics = 0;
v = Args->CheckValue ("-port");
if (v)
{

View File

@ -380,6 +380,8 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
// ... and some items can never be telefragged while others will be telefragged by everything that teleports upon them.
if ((StompAlwaysFrags && !(th->flags6 & MF6_NOTELEFRAG)) || (th->flags7 & MF7_ALWAYSTELEFRAG))
{
// Don't actually damage if predicting a teleport
if (thing->player == NULL || !(thing->player->cheats & CF_PREDICTING))
P_DamageMobj(th, thing, thing, TELEFRAG_DAMAGE, NAME_Telefrag, DMG_THRUSTLESS);
continue;
}
@ -1981,13 +1983,6 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
thing->AdjustFloorClip();
}
// [RH] Don't activate anything if just predicting
if (thing->player && (thing->player->cheats & CF_PREDICTING))
{
thing->flags6 &= ~MF6_INTRYMOVE;
return true;
}
// if any special lines were hit, do the effect
if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP)))
{
@ -1998,7 +1993,11 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
oldside = P_PointOnLineSide(oldx, oldy, ld);
if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER))
{
if (thing->player)
if (thing->player && (thing->player->cheats & CF_PREDICTING))
{
P_PredictLine(ld, thing, oldside, SPAC_Cross);
}
else if (thing->player)
{
P_ActivateLine(ld, thing, oldside, SPAC_Cross);
}
@ -2024,6 +2023,13 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
}
}
// [RH] Don't activate anything if just predicting
if (thing->player && (thing->player->cheats & CF_PREDICTING))
{
thing->flags6 &= ~MF6_INTRYMOVE;
return true;
}
// [RH] Check for crossing fake floor/ceiling
newsec = thing->Sector;
if (newsec->heightsec && oldsec->heightsec && newsec->SecActTarget)

View File

@ -73,6 +73,7 @@
static FRandom pr_playerinspecialsector ("PlayerInSpecialSector");
void P_SetupPortals();
EXTERN_CVAR(Bool, cl_predict_specials)
IMPLEMENT_POINTY_CLASS (DScroller)
DECLARE_POINTER (m_Interpolations[0])
@ -408,6 +409,48 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType)
return true;
}
//============================================================================
//
// P_PredictLine
//
//============================================================================
bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType)
{
int lineActivation;
INTBOOL buttonSuccess;
BYTE special;
// Only predict a very specifc section of specials
if (line->special != Teleport_Line &&
line->special != Teleport)
{
return false;
}
if (!P_TestActivateLine(line, mo, side, activationType) || !cl_predict_specials)
{
return false;
}
if (line->locknumber > 0) return false;
lineActivation = line->activation;
buttonSuccess = false;
buttonSuccess = P_ExecuteSpecial(line->special,
line, mo, side == 1, line->args[0],
line->args[1], line->args[2],
line->args[3], line->args[4]);
special = line->special;
// end of changed code
if (developer && buttonSuccess)
{
Printf("Line special %d predicted on line %i\n", special, int(line - lines));
}
return true;
}
//
// P_PlayerInSpecialSector
// Called every tic frame

View File

@ -166,6 +166,7 @@ void P_UpdateSpecials (void);
// when needed
bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType);
bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType);
bool P_PredictLine (line_t *ld, AActor *mo, int side, int activationType);
void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL);
void P_PlayerOnSpecialFlat (player_t *player, int floorType);

View File

@ -96,6 +96,8 @@ void P_SpawnTeleportFog(fixed_t x, fixed_t y, fixed_t z, int spawnid)
bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
bool useFog, bool sourceFog, bool keepOrientation, bool bHaltVelocity, bool keepHeight)
{
bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING));
fixed_t oldx;
fixed_t oldy;
fixed_t oldz;
@ -181,19 +183,22 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
angle = thing->angle;
}
// Spawn teleport fog at source and destination
if (sourceFog)
if (sourceFog && !predicting)
{
fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
AActor *fog = Spawn<ATeleportFog> (oldx, oldy, oldz + fogDelta, ALLOW_REPLACE);
fog->target = thing;
}
if (useFog)
{
if (!predicting)
{
fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
an = angle >> ANGLETOFINESHIFT;
AActor *fog = Spawn<ATeleportFog> (x + 20*finecosine[an],
y + 20*finesine[an], thing->z + fogDelta, ALLOW_REPLACE);
AActor *fog = Spawn<ATeleportFog>(x + 20 * finecosine[an],
y + 20 * finesine[an], thing->z + fogDelta, ALLOW_REPLACE);
fog->target = thing;
}
if (thing->player)
{
// [RH] Zoom player's field of vision
@ -226,7 +231,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
return true;
}
static AActor *SelectTeleDest (int tid, int tag)
static AActor *SelectTeleDest (int tid, int tag, bool norandom)
{
AActor *searcher;
@ -276,7 +281,7 @@ static AActor *SelectTeleDest (int tid, int tag)
}
else
{
if (count != 1)
if (count != 1 && !norandom)
{
count = 1 + (pr_teleport() % count);
}
@ -323,6 +328,8 @@ static AActor *SelectTeleDest (int tid, int tag)
bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool fog,
bool sourceFog, bool keepOrientation, bool haltVelocity, bool keepHeight)
{
bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING));
AActor *searcher;
fixed_t z;
angle_t angle = 0;
@ -342,7 +349,7 @@ bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool
{ // Don't teleport if hit back of line, so you can get out of teleporter.
return 0;
}
searcher = SelectTeleDest (tid, tag);
searcher = SelectTeleDest(tid, tag, predicting);
if (searcher == NULL)
{
return false;
@ -390,7 +397,7 @@ bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool
thing->velx = FixedMul(velx, c) - FixedMul(vely, s);
thing->vely = FixedMul(vely, c) + FixedMul(velx, s);
}
if ((velx | vely) == 0 && thing->player != NULL && thing->player->mo == thing)
if ((velx | vely) == 0 && thing->player != NULL && thing->player->mo == thing && !predicting)
{
thing->player->mo->PlayIdle ();
}

View File

@ -62,6 +62,7 @@ static FRandom pr_skullpop ("SkullPop");
// Variables for prediction
CVAR (Bool, cl_noprediction, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Bool, cl_predict_specials, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
static player_t PredictionPlayerBackup;
static BYTE PredictionActorBackup[sizeof(AActor)];
static TArray<sector_t *> PredictionTouchingSectorsBackup;
@ -2722,8 +2723,12 @@ void P_PredictPlayer (player_t *player)
}
act->BlockNode = NULL;
bool NoInterpolateOld = R_GetViewInterpolationStatus();
for (int i = gametic; i < maxtic; ++i)
{
if (!NoInterpolateOld)
R_RebuildViewInterpolation(player);
player->cmd = localcmds[i % LOCALCMDTICS];
P_PlayerThink (player);
player->mo->Tick ();

View File

@ -729,6 +729,46 @@ void R_ClearPastViewer (AActor *actor)
}
}
//==========================================================================
//
// R_RebuildViewInterpolation
//
//==========================================================================
void R_RebuildViewInterpolation(player_t *player)
{
InterpolationViewer *iview;
if (NoInterpolateView)
{
if (player != NULL && player->camera != NULL)
{
iview = FindPastViewer(player->camera);
}
if (iview == NULL)
return;
NoInterpolateView = false;
iview->oviewx = iview->nviewx;
iview->oviewy = iview->nviewy;
iview->oviewz = iview->nviewz;
iview->oviewpitch = iview->nviewpitch;
iview->oviewangle = iview->nviewangle;
}
}
//==========================================================================
//
// R_GetViewInterpolationStatus
//
//==========================================================================
bool R_GetViewInterpolationStatus()
{
return NoInterpolateView;
}
//==========================================================================
//
// R_SetupFrame

View File

@ -61,6 +61,8 @@ inline angle_t R_PointToAngle (fixed_t x, fixed_t y) { return R_PointToAngle2 (v
subsector_t *R_PointInSubsector (fixed_t x, fixed_t y);
fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy);
void R_ResetViewInterpolation ();
void R_RebuildViewInterpolation(player_t *player);
bool R_GetViewInterpolationStatus();
void R_SetViewSize (int blocks);
void R_SetFOV (float fov);
float R_GetFOV ();

View File

@ -51,7 +51,7 @@ const char *GetVersionString();
// Version identifier for network games.
// Bump it every time you do a release unless you're certain you
// didn't change anything that will affect sync.
#define NETGAMEVERSION 230
#define NETGAMEVERSION 231
// Version stored in the ini's [LastRun] section.
// Bump it if you made some configuration change that you want to

View File

@ -836,6 +836,7 @@ SCORE_BONUS = "BONUS";
SCORE_COLOR = "COLOR";
SCORE_SECRET = "SECRET";
SCORE_NAME = "NAME";
SCORE_DELAY = "DELAY(ms)";
SCORE_KILLS = "KILLS";
SCORE_FRAGS = "FRAGS";
SCORE_DEATHS = "DEATHS";

View File

@ -341,6 +341,7 @@ OptionMenu "OptionsMenu"
Submenu "Automap Options", "AutomapOptions"
Submenu "HUD Options", "HUDOptions"
Submenu "Miscellaneous Options", "MiscOptions"
Submenu "Network Options", "NetworkOptions"
Submenu "Sound Options", "SoundOptions"
Submenu "Display Options", "VideoOptions"
Submenu "Set video mode", "VideoModeMenu"
@ -805,6 +806,13 @@ OptionValue "AltHUDTime"
9, "System"
}
OptionValue "AltHUDLag"
{
0, "Off"
1, "Netgames only"
2, "Always"
}
OptionMenu "AltHUDOptions"
{
Title "Alternative HUD"
@ -819,6 +827,7 @@ OptionMenu "AltHUDOptions"
Option "Show weapons", "hud_showweapons", "OnOff"
Option "Show time", "hud_showtime", "AltHUDTime"
Option "Time color", "hud_timecolor", "TextColors"
Option "Show network latency", "hud_showlag", "AltHUDLag"
Slider "Red ammo display below %", "hud_ammo_red", 0, 100, 1, 0
Slider "Yellow ammo display below %", "hud_ammo_yellow", 0, 100, 1, 0
Slider "Red health display below", "hud_health_red", 0, 100, 1, 0
@ -1591,3 +1600,28 @@ OptionMenu VideoModeMenu
class VideoModeMenu
}
/*=======================================
*
* Network options menu
*
*=======================================*/
OptionMenu NetworkOptions
{
Title "NETWORK OPTIONS"
StaticText "Local options", 1
Option "Movement prediction", "cl_noprediction", "OffOn"
Option "Predict line actions", "cl_predict_specials", "OnOff"
StaticText " "
StaticText "Host options", 1
Option "Extra Tics", "net_extratic", "ExtraTicMode"
Option "Latency balancing", "net_ticbalance", "OnOff"
}
OptionValue ExtraTicMode
{
0, "None"
1, "1"
2, "All unacknowledged"
}