From b1f87295b86487686b789f9cd730be525bc6fbe6 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Thu, 25 Sep 2014 16:47:41 -0500 Subject: [PATCH 01/21] - Added A_DamageSelf. - A_DamageSelf(int amount, name damagetype) --- src/thingdef/thingdef_codeptr.cpp | 31 +++++++++++++++++++++++++++---- wadsrc/static/actors/actor.txt | 1 + 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index f80e89aad..aff2629e4 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3532,7 +3532,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) //=========================================================================== // -// A_DamageMaster (int amount) +// A_DamageMaster (int amount, str damagetype) // Damages the master of this child by the specified amount. Negative values heal. // //=========================================================================== @@ -3558,7 +3558,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) //=========================================================================== // -// A_DamageChildren (amount) +// A_DamageChildren (amount, str damagetype) // Damages the children of this master by the specified amount. Negative values heal. // //=========================================================================== @@ -3592,7 +3592,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) //=========================================================================== // -// A_DamageSiblings (amount) +// A_DamageSiblings (int amount, str damagetype) // Damages the siblings of this master by the specified amount. Negative values heal. // //=========================================================================== @@ -4993,4 +4993,27 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed) ACTION_PARAM_FIXED(speed, 0); self->Speed = speed; -} +} + +//=========================================================================== +// +// A_DamageSelf (int amount, str damagetype) +// Damages the calling actor by the specified amount. Negative values heal. +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_INT(amount, 0); + ACTION_PARAM_NAME(DamageType, 1); + + if (amount > 0) + { + P_DamageMobj(self, self, self, amount, DamageType, DMG_NO_ARMOR); + } + else if (amount < 0) + { + amount = -amount; + P_GiveBody(self, amount); + } +} \ No newline at end of file diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index e66226c1e..95d055afb 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -304,6 +304,7 @@ ACTOR Actor native //: Thinker action native A_SetDamageType(name damagetype); action native A_DropItem(class item, int dropamount = -1, int chance = 256); action native A_SetSpeed(float speed); + action native A_DamageSelf(int amount, name damagetype = "none"); action native A_CheckSightOrRange(float distance, state label); action native A_CheckRange(float distance, state label); From 542b8a7171a8e5daec4a0ec206c88c9bbde16a9e Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 16 Aug 2014 21:15:39 +1200 Subject: [PATCH 02/21] Added network load balancing - Guests can now attempt to match latency with the arbitrator. (net_loadbalance) - Added althud feature to show arbitrator and local latency. (hud_showlag 1 is on for netgames, 2 is always on) --- src/d_net.cpp | 34 +++++++++++++++++++++++---- src/d_net.h | 1 + src/g_shared/shared_hud.cpp | 47 +++++++++++++++++++++++++++++++++++++ wadsrc/static/menudef.txt | 8 +++++++ 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 9ba6eefa0..8bbe70e43 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -117,6 +117,7 @@ int playerfornode[MAXNETNODES]; int maketic; int skiptics; int ticdup; +int arb_maketic; // Arbitrators maketic difference void D_ProcessEvents (void); void G_BuildTiccmd (ticcmd_t *cmd); @@ -151,6 +152,8 @@ CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } +CVAR(Bool, net_loadbalance, true, CVAR_SERVERINFO) + // [RH] Special "ticcmds" get stored in here static struct TicSpecial { @@ -347,6 +350,9 @@ int NetbufferSize () k += netbuffer[k] + 1; } + if (doomcom.remotenode == nodeforplayer[Net_Arbitrator]) + k++; + if (netbuffer[0] & NCMD_MULTI) { count = netbuffer[k]; @@ -570,6 +576,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 +791,11 @@ void GetPackets (void) } } + if (netconsole == Net_Arbitrator) + { + arb_maketic = netbuffer[k++]; + } + playerbytes[0] = netconsole; if (netbuffer[0] & NCMD_MULTI) { @@ -1190,6 +1204,12 @@ void NetUpdate (void) } } + if (consoleplayer == Net_Arbitrator) + { + // The number of tics we just made should be removed from the count. + netbuffer[k++] = ((maketic - newtics - gametic) / ticdup); + } + if (numtics > 0) { int l; @@ -1298,10 +1318,16 @@ void NetUpdate (void) // 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_PacketServer) + int average = 0; + if (net_loadbalance) + average = (((maketic - newtics - gametic) / ticdup) + arb_maketic) / 2; + if (NetMode == NET_PeerToPeer) { - mastertics = nettics[nodeforplayer[Net_Arbitrator]]; + mastertics = nettics[nodeforplayer[Net_Arbitrator]] + average; + } + else if (NetMode == NET_PacketServer) + { + mastertics = mastertics + average; } if (nettics[0] <= mastertics) { @@ -2713,7 +2739,7 @@ void Net_SkipCommand (int type, BYTE **stream) CCMD (pings) { int i; - + Printf("%d (%d ms) arbitrator buffer time\n", arb_maketic * ticdup, (arb_maketic * ticdup) * (1000 / TICRATE)); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i], diff --git a/src/d_net.h b/src/d_net.h index 4cd3e66f5..8d352b25d 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -143,6 +143,7 @@ extern struct ticcmd_t localcmds[LOCALCMDTICS]; extern int maketic; extern int nettics[MAXNETNODES]; +extern int arb_maketic; extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; extern int ticdup; diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 2daeff7a8..67a6bd82c 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -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 @@ -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,49 @@ 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 localdelay = (maketic - gametic) * (1000 / TICRATE); + int arbitratordelay = (arb_maketic * 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 +1028,7 @@ void DrawHUD() if (idmypos) DrawCoordinates(CPlayer); DrawTime(); + DrawLatency(); } else { diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 324c94e6b..66d7537f6 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -805,6 +805,13 @@ OptionValue "AltHUDTime" 9, "System" } +OptionValue "AltHUDLag" +{ + 0, "Off" + 1, "Netgames only" + 2, "Always" +} + OptionMenu "AltHUDOptions" { Title "Alternative HUD" @@ -819,6 +826,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 From 97586c317ebaba058d25e981b968b90787516a83 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Mon, 18 Aug 2014 21:08:17 +1200 Subject: [PATCH 03/21] Further refinements to network balancing - Added delay times of all players to the scoreboard - Removed balancing from packet-server (tried it, didn't work) - Calculations remove an extra tic to account for possible bias --- src/d_net.cpp | 36 ++++++++++++++++-------------------- src/d_net.h | 4 +++- src/g_shared/shared_hud.cpp | 4 ++-- src/hu_scores.cpp | 26 +++++++++++++++++++------- wadsrc/static/language.enu | 1 + 5 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 8bbe70e43..ff2474464 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -110,6 +110,7 @@ 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]; // Used for storing network delay times. int nodeforplayer[MAXPLAYERS]; int playerfornode[MAXNETNODES]; @@ -117,7 +118,6 @@ int playerfornode[MAXNETNODES]; int maketic; int skiptics; int ticdup; -int arb_maketic; // Arbitrators maketic difference void D_ProcessEvents (void); void G_BuildTiccmd (ticcmd_t *cmd); @@ -152,7 +152,7 @@ CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } -CVAR(Bool, net_loadbalance, true, CVAR_SERVERINFO) +CVAR(Bool, net_ticbalance, false, CVAR_SERVERINFO) // [RH] Special "ticcmds" get stored in here static struct TicSpecial @@ -350,8 +350,8 @@ int NetbufferSize () k += netbuffer[k] + 1; } - if (doomcom.remotenode == nodeforplayer[Net_Arbitrator]) - k++; + // Network delay byte + k++; if (netbuffer[0] & NCMD_MULTI) { @@ -791,10 +791,8 @@ void GetPackets (void) } } - if (netconsole == Net_Arbitrator) - { - arb_maketic = netbuffer[k++]; - } + // Pull current network delay from node + netdelay[netnode] = netbuffer[k++]; playerbytes[0] = netconsole; if (netbuffer[0] & NCMD_MULTI) @@ -1204,11 +1202,9 @@ void NetUpdate (void) } } - if (consoleplayer == Net_Arbitrator) - { - // The number of tics we just made should be removed from the count. - netbuffer[k++] = ((maketic - newtics - gametic) / ticdup); - } + // 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) { @@ -1319,16 +1315,16 @@ void NetUpdate (void) // that it won't adapt. Fortunately, player prediction helps // alleviate the lag somewhat. int average = 0; - if (net_loadbalance) - average = (((maketic - newtics - gametic) / ticdup) + arb_maketic) / 2; + if (NetMode == NET_PeerToPeer) { + // Try to guess ahead the time it takes to send responses to the arbitrator + // [ED850] It seems that there is a bias based on network adaption (which the netwrok arbitrator doesn't do), + // so I have set this up to assume one less tic, which appears to balance it out. + if (net_ticbalance) + average = ((netdelay[0] + ARBITRATOR_DELAY) / 2) - 1; mastertics = nettics[nodeforplayer[Net_Arbitrator]] + average; } - else if (NetMode == NET_PacketServer) - { - mastertics = mastertics + average; - } if (nettics[0] <= mastertics) { gametime--; @@ -2739,7 +2735,7 @@ void Net_SkipCommand (int type, BYTE **stream) CCMD (pings) { int i; - Printf("%d (%d ms) arbitrator buffer time\n", arb_maketic * ticdup, (arb_maketic * ticdup) * (1000 / TICRATE)); + Printf("%d (%d ms) arbitrator buffer time\n", ARBITRATOR_DELAY * ticdup, (ARBITRATOR_DELAY * ticdup) * (1000 / TICRATE)); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i], diff --git a/src/d_net.h b/src/d_net.h index 8d352b25d..1e019031c 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -143,7 +143,9 @@ extern struct ticcmd_t localcmds[LOCALCMDTICS]; extern int maketic; extern int nettics[MAXNETNODES]; -extern int arb_maketic; +extern int netdelay[MAXNETNODES]; +extern int nodeforplayer[MAXPLAYERS]; +#define ARBITRATOR_DELAY netdelay[nodeforplayer[Net_Arbitrator]] extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; extern int ticdup; diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 67a6bd82c..e83e2e988 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -935,8 +935,8 @@ static void DrawLatency() return; } - int localdelay = (maketic - gametic) * (1000 / TICRATE); - int arbitratordelay = (arb_maketic * ticdup) * (1000 / TICRATE); + int localdelay = (netdelay[0] * ticdup) * (1000 / TICRATE); + int arbitratordelay = (ARBITRATOR_DELAY * ticdup) * (1000 / TICRATE); int color = CR_GREEN; if (MAX(localdelay, arbitratordelay) > 200) { diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index af5d1bbaa..7d6c5fb1e 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -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,11 @@ 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); + mysnprintf(str, countof(str), "%d", (netdelay[nodeforplayer[(int)(player - players)]] * 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 ()]; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 4990cb417..a92e22dfe 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -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"; From ded3bc73be14c7606c1970a8cffc0c04bee40b5a Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Mon, 18 Aug 2014 21:46:48 +1200 Subject: [PATCH 04/21] New extratic method - Extratic changed to server var, that can be changed at any time (net_extratic) - Added net_extratic 2 which resends all unconfirmed tics - Corrected bad variable typo in delay reporting --- src/d_net.cpp | 42 +++++++++++++++++++++++++++++------------- src/d_net.h | 1 - src/i_net.cpp | 5 ----- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index ff2474464..466a56c32 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -117,7 +117,7 @@ int playerfornode[MAXNETNODES]; int maketic; int skiptics; -int ticdup; +int ticdup; void D_ProcessEvents (void); void G_BuildTiccmd (ticcmd_t *cmd); @@ -153,6 +153,17 @@ CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } CVAR(Bool, net_ticbalance, false, CVAR_SERVERINFO) +CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO) +{ + if (self < 0) + { + self = 0; + } + else if (self > 3) + { + I_SetFPSLimit(-1); + } +} // [RH] Special "ticcmds" get stored in here static struct TicSpecial @@ -1166,7 +1177,15 @@ void NetUpdate (void) 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] = MAX(0, lowtic); break; + case 1: resendto[i] = MAX(0, lowtic - 1); break; + case 2: resendto[i] = MAX(0, lowtic - (lowtic - nettics[i])); break; + case 3: resendto[i] = MAX(0, lowtic - (BACKUPTICS / 2 - 1)); break; + } if (numtics == 0 && resendOnly && !remoteresend[i] && nettics[i]) { @@ -1204,7 +1223,7 @@ void NetUpdate (void) // Send current network delay // The number of tics we just made should be removed from the count. - netbuffer[k++] = ((maketic - numtics - gametic) / ticdup); + netbuffer[k++] = ((maketic - newtics - gametic) / ticdup); if (numtics > 0) { @@ -1319,7 +1338,7 @@ void NetUpdate (void) if (NetMode == NET_PeerToPeer) { // Try to guess ahead the time it takes to send responses to the arbitrator - // [ED850] It seems that there is a bias based on network adaption (which the netwrok arbitrator doesn't do), + // [ED850] It seems that there is a bias based on network adaption (which the arbitrator doesn't do), // so I have set this up to assume one less tic, which appears to balance it out. if (net_ticbalance) average = ((netdelay[0] + ARBITRATOR_DELAY) / 2) - 1; @@ -1368,9 +1387,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 // @@ -1451,10 +1469,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; @@ -1519,9 +1536,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); diff --git a/src/d_net.h b/src/d_net.h index 1e019031c..64c4e0f43 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -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 diff --git a/src/i_net.cpp b/src/i_net.cpp index 889688b48..e03c2c0e8 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -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) { From 4041f56cc8d9d9105ff86e7d1f7b6d1b0ad00900 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Mon, 18 Aug 2014 21:47:01 +1200 Subject: [PATCH 05/21] Bumped net version --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index c8917212d..92b1816a1 100644 --- a/src/version.h +++ b/src/version.h @@ -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 From 78f8bf19d2f60ffef414a30ab004c082599d658a Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Mon, 18 Aug 2014 22:45:51 +1200 Subject: [PATCH 06/21] Extratics mode 3 didn't work well - Removed Extratics mode 3 - Fixed a typo --- src/d_net.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 466a56c32..84bfe5856 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -159,9 +159,9 @@ CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO) { self = 0; } - else if (self > 3) + else if (self > 2) { - I_SetFPSLimit(-1); + self = 2; } } @@ -1183,8 +1183,7 @@ void NetUpdate (void) default: resendto[i] = MAX(0, lowtic); break; case 1: resendto[i] = MAX(0, lowtic - 1); break; - case 2: resendto[i] = MAX(0, lowtic - (lowtic - nettics[i])); break; - case 3: resendto[i] = MAX(0, lowtic - (BACKUPTICS / 2 - 1)); break; + case 2: resendto[i] = MAX(0, nettics[i]); break; } if (numtics == 0 && resendOnly && !remoteresend[i] && nettics[i]) From c585eee82ba971ca92ffe18d53dd164238f38673 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Mon, 18 Aug 2014 22:55:13 +1200 Subject: [PATCH 07/21] Don't need to MAX() mode 2 --- src/d_net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 84bfe5856..7de859269 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1183,7 +1183,7 @@ void NetUpdate (void) default: resendto[i] = MAX(0, lowtic); break; case 1: resendto[i] = MAX(0, lowtic - 1); break; - case 2: resendto[i] = MAX(0, nettics[i]); break; + case 2: resendto[i] = nettics[i]; break; } if (numtics == 0 && resendOnly && !remoteresend[i] && nettics[i]) From 6cd4fd81518f8e608250cf7c5004208164653392 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Mon, 18 Aug 2014 23:13:41 +1200 Subject: [PATCH 08/21] Added menu options for network settings --- wadsrc/static/menudef.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 66d7537f6..496f1e066 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -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" @@ -1599,3 +1600,27 @@ OptionMenu VideoModeMenu class VideoModeMenu } +/*======================================= + * + * Network options menu + * + *=======================================*/ + +OptionMenu NetworkOptions +{ + Title "NETWORK OPTIONS" + StaticText "Local options", 1 + Option "Movement prediction", "cl_noprediction", "OffOn" + 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" +} From 4db8b3e421d2018ac9d57abf5cbdf249adca4004 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Tue, 19 Aug 2014 22:30:33 +1200 Subject: [PATCH 09/21] Made delay updates less erratic --- src/d_net.cpp | 15 +++++++++++---- src/d_net.h | 3 +-- src/g_shared/shared_hud.cpp | 8 +++++--- src/hu_scores.cpp | 9 ++++++++- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 7de859269..6e2877495 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -110,7 +110,7 @@ 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]; // Used for storing network delay times. +int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times. int nodeforplayer[MAXPLAYERS]; int playerfornode[MAXNETNODES]; @@ -803,7 +803,7 @@ void GetPackets (void) } // Pull current network delay from node - netdelay[netnode] = netbuffer[k++]; + netdelay[netnode][(nettics[netnode]+1) % BACKUPTICS] = netbuffer[k++]; playerbytes[0] = netconsole; if (netbuffer[0] & NCMD_MULTI) @@ -1340,7 +1340,15 @@ void NetUpdate (void) // [ED850] It seems that there is a bias based on network adaption (which the arbitrator doesn't do), // so I have set this up to assume one less tic, which appears to balance it out. if (net_ticbalance) - average = ((netdelay[0] + ARBITRATOR_DELAY) / 2) - 1; + { + for (i = 0; i < BACKUPTICS; i++) + { + average += netdelay[nodeforplayer[Net_Arbitrator]][i]; + } + average /= BACKUPTICS; + average = ((netdelay[0][nettics[0] % BACKUPTICS] + average) / 2) - 1; + } + mastertics = nettics[nodeforplayer[Net_Arbitrator]] + average; } if (nettics[0] <= mastertics) @@ -2750,7 +2758,6 @@ void Net_SkipCommand (int type, BYTE **stream) CCMD (pings) { int i; - Printf("%d (%d ms) arbitrator buffer time\n", ARBITRATOR_DELAY * ticdup, (ARBITRATOR_DELAY * ticdup) * (1000 / TICRATE)); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i], diff --git a/src/d_net.h b/src/d_net.h index 64c4e0f43..07921a301 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -142,9 +142,8 @@ extern struct ticcmd_t localcmds[LOCALCMDTICS]; extern int maketic; extern int nettics[MAXNETNODES]; -extern int netdelay[MAXNETNODES]; +extern int netdelay[MAXNETNODES][BACKUPTICS]; extern int nodeforplayer[MAXPLAYERS]; -#define ARBITRATOR_DELAY netdelay[nodeforplayer[Net_Arbitrator]] extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; extern int ticdup; diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index e83e2e988..110675791 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -934,9 +934,11 @@ static void DrawLatency() { return; } - - int localdelay = (netdelay[0] * ticdup) * (1000 / TICRATE); - int arbitratordelay = (ARBITRATOR_DELAY * ticdup) * (1000 / TICRATE); + 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) { diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index 7d6c5fb1e..8b9a7d0ad 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -419,7 +419,14 @@ 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); - mysnprintf(str, countof(str), "%d", (netdelay[nodeforplayer[(int)(player - players)]] * ticdup) * (1000 / TICRATE)); + 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); From 42e6737803adfd3984ea3481667c0d668165f92e Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Tue, 19 Aug 2014 22:31:45 +1200 Subject: [PATCH 10/21] Player prediction now updates listener --- src/p_user.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_user.cpp b/src/p_user.cpp index fbe24cc83..9c3d7f321 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2728,6 +2728,8 @@ void P_PredictPlayer (player_t *player) P_PlayerThink (player); player->mo->Tick (); } + + S_UpdateSounds(players[consoleplayer].camera); // move positional sounds } extern msecnode_t *P_AddSecnode (sector_t *s, AActor *thing, msecnode_t *nextnode); From c661da299592b16981425edbf06914e5f4dcbc2f Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Wed, 20 Aug 2014 19:41:07 +1200 Subject: [PATCH 11/21] Stop negative tic counts from corrupting messages --- src/d_net.cpp | 2 +- src/i_net.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 6e2877495..dfee7460e 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1173,7 +1173,7 @@ 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); diff --git a/src/i_net.cpp b/src/i_net.cpp index e03c2c0e8..3ec9d7881 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -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; From 530f4746731ac6d13c7b86646b84f4b996dd7d1a Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Thu, 21 Aug 2014 16:31:29 +1200 Subject: [PATCH 12/21] Shifted netmode reporting for guests - The netmode is now reported after a guest has received it. - Minor code cleanup --- src/d_net.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index dfee7460e..fb6e9722d 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1173,7 +1173,7 @@ void NetUpdate (void) netbuffer[k++] = lowtic; } - numtics = MAX(0, lowtic - realstart); + numtics = lowtic - realstart; if (numtics > BACKUPTICS) I_Error ("NetUpdate: Node %d missed too many tics", i); @@ -1181,12 +1181,12 @@ void NetUpdate (void) { case 0: default: - resendto[i] = MAX(0, lowtic); break; + 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]) + if (numtics <= 0 && resendOnly && !remoteresend[i] && nettics[i]) { continue; } @@ -1692,15 +1692,18 @@ 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"); + } } // [RH] Setup user info @@ -1728,6 +1731,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); } From ad0a1ad86576a5b5fd0205f9eb6de895dc4feccd Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Thu, 21 Aug 2014 16:41:59 +1200 Subject: [PATCH 13/21] Readded -extratic for compatibility with launchers --- src/d_net.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/d_net.cpp b/src/d_net.cpp index fb6e9722d..06886e175 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1704,6 +1704,11 @@ void D_CheckNetGame (void) 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 From 53b6e7d4d537c204646012bdb03b8f607402f6ee Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 23 Aug 2014 15:17:11 +1200 Subject: [PATCH 14/21] Added silent line teleport prediction - Allow activation of line teleport specials during prediction - Moved prediction functions to improve uncapped framerates --- src/d_main.cpp | 4 ++-- src/p_map.cpp | 24 +++++++++++++++--------- src/p_spec.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ src/p_spec.h | 1 + src/p_user.cpp | 7 +++++-- src/r_utility.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/r_utility.h | 2 ++ 7 files changed, 107 insertions(+), 13 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index ab33bfaec..8a8751041 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -756,9 +756,9 @@ void D_Display () } screen->SetBlendingRect(viewwindowx, viewwindowy, viewwindowx + viewwidth, viewwindowy + viewheight); - P_PredictPlayer(&players[consoleplayer]); + //P_PredictPlayer(&players[consoleplayer]); Renderer->RenderView(&players[consoleplayer]); - P_UnPredictPlayer(); + //P_UnPredictPlayer(); if ((hw2d = screen->Begin2D(viewactive))) { // Redraw everything every frame when using 2D accel diff --git a/src/p_map.cpp b/src/p_map.cpp index 2274e7571..f0087e220 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -380,7 +380,9 @@ 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)) { - P_DamageMobj(th, thing, thing, TELEFRAG_DAMAGE, NAME_Telefrag, DMG_THRUSTLESS); + // 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; } return false; @@ -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) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 00ed322c0..4ac1c59d9 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -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,47 @@ 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) + { + 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 diff --git a/src/p_spec.h b/src/p_spec.h index c9bb6eded..906a38a8c 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -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); diff --git a/src/p_user.cpp b/src/p_user.cpp index 9c3d7f321..7b049a2df 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -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 PredictionTouchingSectorsBackup; @@ -2722,14 +2723,16 @@ 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 (); } - - S_UpdateSounds(players[consoleplayer].camera); // move positional sounds } extern msecnode_t *P_AddSecnode (sector_t *s, AActor *thing, msecnode_t *nextnode); diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 5bf38ad26..19d446b5b 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -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 diff --git a/src/r_utility.h b/src/r_utility.h index 85ca7c410..2d9aac086 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -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 (); From 9e68983b4469906102b7d810fe02e1756d5a3540 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Tue, 26 Aug 2014 22:29:39 +1200 Subject: [PATCH 15/21] Added standard teleports to line prediction - Added standard teleports to line prediction - Menudef for line special prediction --- src/p_spec.cpp | 3 ++- src/p_teleport.cpp | 27 +++++++++++++++++---------- wadsrc/static/menudef.txt | 1 + 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 4ac1c59d9..d58062a7e 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -422,7 +422,8 @@ bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType) BYTE special; // Only predict a very specifc section of specials - if (line->special != Teleport_Line) + if (line->special != Teleport_Line && + line->special != Teleport) { return false; } diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 50470d9eb..b64c04a5a 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -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,7 +183,7 @@ 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 (oldx, oldy, oldz + fogDelta, ALLOW_REPLACE); @@ -189,11 +191,14 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, } if (useFog) { - fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; - an = angle >> ANGLETOFINESHIFT; - AActor *fog = Spawn (x + 20*finecosine[an], - y + 20*finesine[an], thing->z + fogDelta, ALLOW_REPLACE); - fog->target = thing; + if (!predicting) + { + fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; + an = angle >> ANGLETOFINESHIFT; + AActor *fog = Spawn(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 (); } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 496f1e066..6d313faf1 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1611,6 +1611,7 @@ 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" From 8f82243f4c5a3ca729aa5e400b3447b64d8965e1 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Tue, 26 Aug 2014 22:31:42 +1200 Subject: [PATCH 16/21] Don't balance if already the slowest node - Network balancing shouldn't be run if already too far behind - Don't save network settings - Added net_fakelatency for debug builds --- src/d_net.cpp | 125 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 13 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 06886e175..eb8cb4eeb 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -152,8 +152,8 @@ CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } -CVAR(Bool, net_ticbalance, false, CVAR_SERVERINFO) -CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO) +CVAR(Bool, net_ticbalance, false, CVAR_SERVERINFO | CVAR_NOSAVE) +CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO | CVAR_NOSAVE) { if (self < 0) { @@ -165,6 +165,19 @@ CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO) } } +#ifdef _DEBUG +CVAR(Int, net_fakelatency, 0, 0); + +struct PacketStore +{ + int timer; + doomcom_t message; +}; + +static TArray InBuffer; +static TArray OutBuffer; +#endif + // [RH] Special "ticcmds" get stored in here static struct TicSpecial { @@ -504,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 } // @@ -526,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) { @@ -1173,7 +1239,7 @@ 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); @@ -1186,7 +1252,7 @@ void NetUpdate (void) case 2: resendto[i] = nettics[i]; break; } - if (numtics <= 0 && resendOnly && !remoteresend[i] && nettics[i]) + if (numtics == 0 && resendOnly && !remoteresend[i] && nettics[i]) { continue; } @@ -1332,24 +1398,49 @@ void NetUpdate (void) // 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. - int average = 0; if (NetMode == NET_PeerToPeer) { - // Try to guess ahead the time it takes to send responses to the arbitrator + // Try to guess ahead the time it takes to send responses to the slowest node // [ED850] It seems that there is a bias based on network adaption (which the arbitrator doesn't do), // so I have set this up to assume one less tic, which appears to balance it out. + int totalavg = 0; if (net_ticbalance) { - for (i = 0; i < BACKUPTICS; i++) + // We shouldn't adapt if we are already the slowest node, otherwise it just adds more latency + bool slow = true; + int nodeavg = 0; + for (i = 1; i < MAXNETNODES; i++) { - average += netdelay[nodeforplayer[Net_Arbitrator]][i]; + if (!nodeingame[i]) + continue; + + if (netdelay[i][0] > netdelay[0][0]) + { + slow = false; + break; + } + } + + if (!slow) + { + int totalnodes = 0; + for (i = 0; i < MAXNETNODES; i++) + { + if (!nodeingame[i]) + continue; + + totalnodes++; + nodeavg = 0; + for (j = 0; j < BACKUPTICS; j++) nodeavg += netdelay[i][j]; + totalavg += (nodeavg / BACKUPTICS); + } + + totalavg = (totalavg / totalnodes) - 1; } - average /= BACKUPTICS; - average = ((netdelay[0][nettics[0] % BACKUPTICS] + average) / 2) - 1; } - mastertics = nettics[nodeforplayer[Net_Arbitrator]] + average; + mastertics = nettics[nodeforplayer[Net_Arbitrator]] + totalavg; } if (nettics[0] <= mastertics) { @@ -1867,6 +1958,9 @@ void TryRunTics (void) { C_Ticker(); M_Ticker(); + // Repredict the player for new buffered movement + P_UnPredictPlayer(); + P_PredictPlayer(&players[consoleplayer]); } return; } @@ -1902,6 +1996,9 @@ void TryRunTics (void) { C_Ticker (); M_Ticker (); + // Repredict the player for new buffered movement + P_UnPredictPlayer(); + P_PredictPlayer(&players[consoleplayer]); return; } } @@ -1915,6 +2012,7 @@ void TryRunTics (void) // run the count tics if (counts > 0) { + P_UnPredictPlayer(); while (counts--) { if (gametic > lowtic) @@ -1934,6 +2032,7 @@ void TryRunTics (void) NetUpdate (); // check for new console commands } + P_PredictPlayer(&players[consoleplayer]); S_UpdateSounds (players[consoleplayer].camera); // move positional sounds } } From 84cf79980397df87594816452fc917fdd2da6899 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Fri, 26 Sep 2014 15:37:14 +1200 Subject: [PATCH 17/21] Final changes to balancing --- src/d_net.cpp | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index eb8cb4eeb..c0585a366 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -111,6 +111,7 @@ 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]; @@ -1407,36 +1408,26 @@ void NetUpdate (void) int totalavg = 0; if (net_ticbalance) { - // We shouldn't adapt if we are already the slowest node, otherwise it just adds more latency - bool slow = true; - int nodeavg = 0; - for (i = 1; i < MAXNETNODES; i++) - { - if (!nodeingame[i]) - continue; + // We shouldn't adapt if we are already the slower then the arbitrator, otherwise it just adds more latency + int nodeavg = 0, arbavg = 0; - if (netdelay[i][0] > netdelay[0][0]) - { - slow = false; - break; - } + for (j = 0; j < BACKUPTICS; j++) + { + arbavg += netdelay[nodeforplayer[Net_Arbitrator]][j]; + nodeavg += netdelay[0][j]; } + arbavg /= BACKUPTICS; + nodeavg /= BACKUPTICS; - if (!slow) + if (arbavg > nodeavg) { - int totalnodes = 0; - for (i = 0; i < MAXNETNODES; i++) - { - if (!nodeingame[i]) - continue; - - totalnodes++; - nodeavg = 0; - for (j = 0; j < BACKUPTICS; j++) nodeavg += netdelay[i][j]; - totalavg += (nodeavg / BACKUPTICS); - } - - totalavg = (totalavg / totalnodes) - 1; + lastaverage = totalavg = ((arbavg + nodeavg) / 2); + } + else + { + if (nodeavg > (arbavg + 2) && lastaverage > 0) + lastaverage--; + totalavg = lastaverage; } } From e25b91d5a1abf72f172a311fac0ed19882f4a1a8 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Fri, 26 Sep 2014 16:11:52 +1200 Subject: [PATCH 18/21] Cleanup --- src/d_main.cpp | 4 ++-- src/d_net.cpp | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 8a8751041..a24586bc4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -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 diff --git a/src/d_net.cpp b/src/d_net.cpp index c0585a366..d33f47e38 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1402,13 +1402,10 @@ void NetUpdate (void) if (NetMode == NET_PeerToPeer) { - // Try to guess ahead the time it takes to send responses to the slowest node - // [ED850] It seems that there is a bias based on network adaption (which the arbitrator doesn't do), - // so I have set this up to assume one less tic, which appears to balance it out. int totalavg = 0; if (net_ticbalance) { - // We shouldn't adapt if we are already the slower then the arbitrator, otherwise it just adds more latency + // 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++) @@ -1419,12 +1416,14 @@ void NetUpdate (void) 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; From 422e83a1b91dd749288f1314689db08f722ce340 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Thu, 25 Sep 2014 23:12:25 -0500 Subject: [PATCH 19/21] - Added more A_Damage functions: - A_DamageTarget - A_DamageTracer -Both take a number for how much damage to deal and the damagetype to inflict. Negative numbers means healing. --- src/thingdef/thingdef_codeptr.cpp | 64 ++++++++++++++++++++++++++++--- wadsrc/static/actors/actor.txt | 2 + 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index aff2629e4..6c44fa79e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5007,13 +5007,67 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) ACTION_PARAM_INT(amount, 0); ACTION_PARAM_NAME(DamageType, 1); - if (amount > 0) + if (amount > 0) + { + P_DamageMobj(self, self, self, amount, DamageType, DMG_NO_ARMOR); + } + else if (amount < 0) + { + amount = -amount; + P_GiveBody(self, amount); + } +} + +//=========================================================================== +// +// A_DamageTarget (int amount, str damagetype) +// Damages the target of the actor by the specified amount. Negative values heal. +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_INT(amount, 0); + ACTION_PARAM_NAME(DamageType, 1); + + if (self->target != NULL) { - P_DamageMobj(self, self, self, amount, DamageType, DMG_NO_ARMOR); + + if (amount > 0) + { + P_DamageMobj(self->target, self, self, amount, DamageType, DMG_NO_ARMOR); + } + else if (amount < 0) + { + amount = -amount; + P_GiveBody(self->target, amount); + } } - else if (amount < 0) +} + +//=========================================================================== +// +// A_DamageTracer (int amount, str damagetype) +// Damages the tracer of the actor by the specified amount. Negative values heal. +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_INT(amount, 0); + ACTION_PARAM_NAME(DamageType, 1); + + if (self->target != NULL) { - amount = -amount; - P_GiveBody(self, amount); + + if (amount > 0) + { + P_DamageMobj(self->tracer, self, self, amount, DamageType, DMG_NO_ARMOR); + } + else if (amount < 0) + { + amount = -amount; + P_GiveBody(self->tracer, amount); + } } } \ No newline at end of file diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 95d055afb..448d83f09 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -305,6 +305,8 @@ ACTOR Actor native //: Thinker action native A_DropItem(class item, int dropamount = -1, int chance = 256); action native A_SetSpeed(float speed); action native A_DamageSelf(int amount, name damagetype = "none"); + action native A_DamageTarget(int amount, name damagetype = "none"); + action native A_DamageTracer(int amount, name damagetype = "none"); action native A_CheckSightOrRange(float distance, state label); action native A_CheckRange(float distance, state label); From 6586fa29fd67323978a15376fd91c5a3945938ea Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Thu, 25 Sep 2014 23:56:10 -0500 Subject: [PATCH 20/21] - Added FDARI's A_JumpIf CheckClass submission. - bool CheckClass(string classname, int ptr_select = aaptr_default, bool match_superclass = false) --- src/namedef.h | 1 + src/thingdef/thingdef_function.cpp | 76 ++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index a4c8da638..1e7fbd0d3 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -298,6 +298,7 @@ xx(Abs) xx(ACS_NamedExecuteWithResult) xx(CallACS) xx(Sqrt) +xx(CheckClass) // Various actor names which are used internally xx(MapSpot) diff --git a/src/thingdef/thingdef_function.cpp b/src/thingdef/thingdef_function.cpp index 2858e9a86..9bf80dcaa 100644 --- a/src/thingdef/thingdef_function.cpp +++ b/src/thingdef/thingdef_function.cpp @@ -43,6 +43,8 @@ #include "tarray.h" #include "thingdef.h" #include "thingdef_exp.h" +#include "actor.h" +#include "actorptrselect.h" static TMap CreatorMap; @@ -185,3 +187,77 @@ public: GLOBALFUNCTION_ADDER(Sqrt); +//========================================================================== +// +// Function: checkclass +// +//========================================================================== + +class FxGlobalFunctionCall_CheckClass : public FxGlobalFunctionCall +{ + public: + GLOBALFUNCTION_DEFINE(CheckClass); + + FxExpression *Resolve(FCompileContext& ctx) + { + CHECKRESOLVED(); + + if (!ResolveArgs(ctx, 1, 3, false)) + return NULL; + + for (int i = ArgList->Size(); i > 1;) + { + if (!(*ArgList)[--i]->ValueType.isNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); + delete this; + return NULL; + } + } + + switch ((*ArgList)[0]->ValueType.Type) + { + case VAL_Class: case VAL_Name:break; + default: + ScriptPosition.Message(MSG_ERROR, "actor class expected for parameter"); + delete this; + return NULL; + } + + ValueType = VAL_Float; + return this; + } + + ExpVal EvalExpression(AActor *self) + { + ExpVal ret; + ret.Type = VAL_Int; + + const PClass * checkclass; + { + ExpVal v = (*ArgList)[0]->EvalExpression(self); + checkclass = v.GetClass(); + if (!checkclass) + { + checkclass = PClass::FindClass(v.GetName()); + if (!checkclass) { ret.Int = 0; return ret; } + } + } + + bool match_superclass = false; + int pick_pointer = AAPTR_DEFAULT; + + switch (ArgList->Size()) + { + case 3: match_superclass = (*ArgList)[2]->EvalExpression(self).GetBool(); + case 2: pick_pointer = (*ArgList)[1]->EvalExpression(self).GetInt(); + } + + self = COPY_AAPTR(self, pick_pointer); + if (!self){ ret.Int = 0; return ret; } + ret.Int = match_superclass ? checkclass->IsAncestorOf(self->GetClass()) : checkclass == self->GetClass(); + return ret; + } + }; + +GLOBALFUNCTION_ADDER(CheckClass); \ No newline at end of file From 54ccf5d44d0facf13f6d1af8c5ef9531daafad1c Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Fri, 26 Sep 2014 10:52:11 +0200 Subject: [PATCH 21/21] - Fixed a possible uninitialized condition. In the function R_RebuildViewInterpolation, the pointer 'iview' was not initialized when the player or its camera were NULL, hence 'iview == NULL' was garbage. Also, the function FindPastViewer does not return NULL, hence the mentioned check is not needed at all. Just return early if the player camera does not exist. --- src/r_utility.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 19d446b5b..585e3dcf3 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -737,24 +737,20 @@ void R_ClearPastViewer (AActor *actor) void R_RebuildViewInterpolation(player_t *player) { - InterpolationViewer *iview; - if (NoInterpolateView) - { - if (player != NULL && player->camera != NULL) - { - iview = FindPastViewer(player->camera); - } + if (player == NULL || player->camera == NULL) + return; - if (iview == NULL) - return; + if (!NoInterpolateView) + return; + NoInterpolateView = false; - NoInterpolateView = false; - iview->oviewx = iview->nviewx; - iview->oviewy = iview->nviewy; - iview->oviewz = iview->nviewz; - iview->oviewpitch = iview->nviewpitch; - iview->oviewangle = iview->nviewangle; - } + InterpolationViewer *iview = FindPastViewer(player->camera); + + iview->oviewx = iview->nviewx; + iview->oviewy = iview->nviewy; + iview->oviewz = iview->nviewz; + iview->oviewpitch = iview->nviewpitch; + iview->oviewangle = iview->nviewangle; } //==========================================================================